
Kumusta sa lahat!
Π Sa bahaging ito, tinalakay namin nang detalyado kung paano lumikha at gumamit ng dApp (desentralisadong aplikasyon) sa .
Subukan natin nang kaunti ang na-disassemble na ngayon .
Hakbang 3: Pagsubok sa dApp account

Anong mga problema ang agad na pumupukaw sa iyong atensyon ni Alice? dApp Account?
Una:
Maaaring aksidenteng magpadala sina Boob at Cooper ng pondo sa isang dApp address gamit ang isang regular ilipat mga transaksyon at sa gayon ay hindi na nila maa-access muli ang mga ito.Pangalawa:
Hindi namin pinaghihigpitan si Alice sa pag-withdraw ng pondo nang walang pag-apruba mula kina Boob o Cooper. Gaya ng nakikita mo, lahat ng transaksyon mula kay Alice ay isasagawa.
Ayusin natin ang pangalawa sa pamamagitan ng pag-ban kay Alice ilipat mga transaksyon. Pag-deploy ng naitama na script:

οΏΌ
Sinusubukan naming mag-withdraw ng mga coin mula sa dApp ni Alice at sa signature nito. Nakakakuha kami ng error:

Subukan nating mag-withdraw gamit ang withdraw:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))
Gumagana ang script at naayos na natin ang punto 2!
Hakbang 4: Gumawa ng DAO gamit ang pagboto
Sa kasamaang palad, ang wikang RIDE ay hindi pa nagbibigay ng mga kakayahan para sa pagtatrabaho sa mga koleksyon (mga diksyunaryo ng mga diksyunaryo, mga iterator, mga reducer, atbp.). Gayunpaman, para sa anumang operasyon na may mga flat collection mahalagang halaga Maaari tayong magdisenyo ng isang sistema para sa pagtatrabaho gamit ang mga string, nang naaayon sa mga key at sa kanilang decryption.
Napakadaling pagdugtungin ang mga string, maaaring hatiin ang mga string gamit ang mga index.
Bilang isang halimbawa ng pagsubok, ating tipunin at i-parse ang isang string at suriin kung paano nito naaapektuhan ang resulta ng transaksyon.
Hindi natuloy ang pagpirma ni Alice sa transaksyon ng Transfer dahil naharang ang kakayahang ito sa @verifier para sa ganitong uri ng transaksyon.
Magsanay tayo gamit ang mga tali at pagkatapos ay lutasin ito.
Mga Kuwerdas ng RIDE
Posible na ulit ang transaksyon, alam na natin kung paano gumamit ng mga string.

οΏΌ
Kaya, mayroon tayo ng lahat ng kailangan natin para magsulat ng kumplikadong lohika. DAO dApp.
Mga Transaksyon ng Datos
Mga Transaksyon ng Datos:
"Ang pinakamataas na laki para sa isang susi ay 100 karakter, at ang isang susi ay maaaring maglaman ng mga arbitraryong Unicode code point kabilang ang mga espasyo at iba pang hindi maaaring i-print na mga simbolo. Ang mga halaga ng string ay may limitasyon na 32,768 bytes at ang pinakamataas na bilang ng mga posibleng entry sa transaksyon ng data ay 100. Sa pangkalahatan, ang pinakamataas na laki ng isang transaksyon ng data ay nasa humigit-kumulang 140kb β bilang sanggunian, halos eksaktong haba ng dula ni Shakespeare na 'Romeo and Juliet'."
Gumagawa kami ng DAO na may mga sumusunod na kondisyon:
Para makatanggap ng pondo ang isang startup sa pamamagitan ng pagtawag kumuha ng mga Pondo() Kinakailangan ang suporta ng kahit 2 kalahok β mga mamumuhunan ng DAO. Mag-withdraw magiging posible na magkaroon ng eksaktong dami ng kabuuang nakasaad sa pagboto Mga may-ari ng DAO.
Gumawa tayo ng 3 uri ng mga susi at magdagdag ng lohika para sa pagtatrabaho sa mga balanse sa 2 bagong function, bumoto at kumuha ng mga pondo:
xxβ¦xx_ia = mga mamumuhunan, magagamit na balanse (boto, deposito, pag-withdraw)
xxβ¦xx_sv = mga startup, bilang ng mga boto (boto, kumuha ng mga pondo)
xxβ¦xx_sf = mga startup, bilang ng mga boto (boto, kumuha ng mga pondo)
xxβ¦xx = pampublikong adres (35 karakter)
Tandaan na sa Vote kailangan naming i-update ang ilang field nang sabay-sabay:
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),
Pinapayagan tayo ng WriteSet na gumawa ng maraming talaan nang sabay-sabay sa loob ng isa invokeScript mga transaksyon.
Ganito ang hitsura sa DAO dApp key-value store pagkatapos mag-refill nina Bob at Cooper ia-mga deposito:

Bahagyang nagbago ang aming tungkulin sa pagdeposito:

Ngayon ay dumating ang pinakamahalagang sandali sa mga aktibidad ng DAO - bumoto para sa mga proyektong kailangang pondohan.
Bumoto si Bob para sa proyektong 500000 wavelets ni Neli:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))

Sa data warehouse, makikita natin ang lahat ng kinakailangang rekord para sa address ni Neli:

Bumoto rin si Cooper para sa proyektong Neli.

Tingnan natin ang function code kumuha ng mga PondoKailangang makakuha si Neli ng kahit dalawang boto para makapag-withdraw ng pondo mula sa DAO.

Babawiin ni Neli ang kalahati ng halagang ipinagkatiwala sa kanya:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))

Nagtatagumpay siya, ibig sabihin, gumagana ang DAO!
Natalakay na natin ang proseso ng paggawa ng DAO sa wikang RIDE4DAPPS.
Sa mga susunod na bahagi, susuriin natin nang mas malapitan ang code refactoring at case testing.
Ang buong bersyon ng code ay nasa
# In this example multiple accounts can deposit their funds to DAO and safely take them back, no one can interfere with this.
# DAO participants can also vote for particular addresses and let them withdraw invested funds then quorum has reached.
# An inner state is maintained as mapping `address=>waves`.
# https://medium.com/waves-lab/waves-announces-funding-for-ride-for-dapps-developers-f724095fdbe1
# You can try this contract by following commands in the IDE (ide.wavesplatform.com)
# Run commands as listed below
# From account #0:
# deploy()
# From account #1: deposit funds
# broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"deposit",args:[]}, payment: [{amount: 100000000, asset:null }]}))
# From account #2: deposit funds
# broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"deposit",args:[]}, payment: [{amount: 100000000, asset:null }]}))
# From account #1: vote for startup
# broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
# From account #2: vote for startup
# broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
# From account #3: get invested funds
# broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))
{-# STDLIB_VERSION 3 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}
@Callable(i)
func deposit() = {
let pmt = extract(i.payment)
if (isDefined(pmt.assetId)) then throw("can hodl waves only at the moment")
else {
let currentKey = toBase58String(i.caller.bytes)
let xxxInvestorBalance = currentKey + "_" + "ib"
let currentAmount = match getInteger(this, xxxInvestorBalance) {
case a:Int => a
case _ => 0
}
let newAmount = currentAmount + pmt.amount
WriteSet([DataEntry(xxxInvestorBalance, newAmount)])
}
}
@Callable(i)
func withdraw(amount: Int) = {
let currentKey = toBase58String(i.caller.bytes)
let xxxInvestorBalance = currentKey + "_" + "ib"
let currentAmount = match getInteger(this, xxxInvestorBalance) {
case a:Int => a
case _ => 0
}
let newAmount = currentAmount - amount
if (amount < 0)
then throw("Can't withdraw negative amount")
else if (newAmount < 0)
then throw("Not enough balance")
else ScriptResult(
WriteSet([DataEntry(xxxInvestorBalance, newAmount)]),
TransferSet([ScriptTransfer(i.caller, amount, unit)])
)
}
@Callable(i)
func getFunds(amount: Int) = {
let quorum = 2
let currentKey = toBase58String(i.caller.bytes)
let xxxStartupFund = currentKey + "_" + "sf"
let xxxStartupVotes = currentKey + "_" + "sv"
let currentAmount = match getInteger(this, xxxStartupFund) {
case a:Int => a
case _ => 0
}
let totalVotes = match getInteger(this, xxxStartupVotes) {
case a:Int => a
case _ => 0
}
let newAmount = currentAmount - amount
if (amount < 0)
then throw("Can't withdraw negative amount")
else if (newAmount < 0)
then throw("Not enough balance")
else if (totalVotes < quorum)
then throw("Not enough votes. At least 2 votes required!")
else ScriptResult(
WriteSet([
DataEntry(xxxStartupFund, newAmount)
]),
TransferSet([ScriptTransfer(i.caller, amount, unit)])
)
}
@Callable(i)
func vote(amount: Int, address: String) = {
let currentKey = toBase58String(i.caller.bytes)
let xxxInvestorBalance = currentKey + "_" + "ib"
let xxxStartupFund = address + "_" + "sf"
let xxxStartupVotes = address + "_" + "sv"
let currentAmount = match getInteger(this, xxxInvestorBalance) {
case a:Int => a
case _ => 0
}
let currentVotes = match getInteger(this, xxxStartupVotes) {
case a:Int => a
case _ => 0
}
let currentFund = match getInteger(this, xxxStartupFund) {
case a:Int => a
case _ => 0
}
if (amount <= 0)
then throw("Can't withdraw negative amount")
else if (amount > currentAmount)
then throw("Not enough balance")
else ScriptResult(
WriteSet([
DataEntry(xxxInvestorBalance, currentAmount - amount),
DataEntry(xxxStartupVotes, currentVotes + 1),
DataEntry(xxxStartupFund, currentFund + amount)
]),
TransferSet([ScriptTransfer(i.caller, amount, unit)])
)
}
@Verifier(tx)
func verify() = {
match tx {
case t: TransferTransaction =>false
case _ => true
}
}
Pinagmulan: www.habr.com
