
Tere kÔigile!
V osa jooksul vaatlesime pÔhjalikult, kuidas luua ja töötada dApp (detsentraliseeritud rakendus) .
Katsetame nĂŒĂŒd veidi Ă€ra vĂ”etud .
Etapp 3. dApp konto testimine

Millised probleemid viskuvad kohe silma Alice dApp konto?
Esiteks:
Boob ja Cooper vÔivad juhuslikult saata dApp aadressile vahendeid tavatransaktsiooni kaudu ja seega ei saa nad neile enam juurde pÀÀseda. transfer Teiseks:Me ei piira kuidagi Alice'i vahendite tÔmbamist ilma Boobi vÔi Cooperiga kokku leppimata. Pange tÀhele, et kÔik Alice'i tehingud tÀidetakse.
Parandame teise, keelates Alice'i
tehingud. Juurutame parandatud skripti: transfer Proovime vĂ€lja vĂ”tta mĂŒnte Alice'i ja tema allkirjaga. Saame vea:

ïżŒ
Proovime vÀlja vÔtta withdraw kaudu:

broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))
Skript töötab ning saime teise punkti selgeks!Etapp 4. Loome DAO koos hÀÀletamisega
Samm 4. Loome hÀÀletamise DAO
Kahjuks ei ole RIDE keeles yet olemas vĂ”imalusi kollektiividega (sĂ”nastikud-sĂ”nastiked, iteratsioonid, reduktorid jne) töötamiseks. Siiski, kĂ”ikide toimingute puhul tasapinnaliste kollektsioonidega vĂ”ti-vÀÀrtus saame kavandada sĂŒsteemi, mis tegeleb stringide, seega ka vĂ”tmete ja nende deĆĄifreerimisega.
Stringe on vĂ€ga lihtne ĂŒhendama, stringe saab indekseid mööda jagada.
LÀhme testnÀitena stringi koostama ja lahendame selle, et vaadata, kuidas see mÔjutab tehingu tulemust.
JĂ”udsime sinnani, et Alice ei saanud Transfer tehingut allkirjastada, kuna see vĂ”imalus oli @verifier'is selle tĂŒĂŒbi tehingute jaoks blokeeritud.
Harjutame stringidega ja lahendame siis selle kĂŒsimuse.
RIDE stringid
Tehing on jÀlle vÔimalik, saame stringidega töötada.

ïżŒ
KokkuvÔttes on meil kÔik vajalik keeruka loogika kirjutamiseks DAO dApp.
Andmete tehingud
Andmete tehingud:
âVĂ”ti maksimaalne suurus on 100 tĂ€hemĂ€rki ja vĂ”ti vĂ”ib sisaldada juhuslikke Unicode koodipunkte, sealhulgas tĂŒhikuid ja muid trĂŒkkimata sĂŒmboleid. Stringide vÀÀrtuste suurus on piiratud 32 768 baitiga ja andmete tehingute maksimaalne vĂ”imalike sisestuste arv on 100. Ăldiselt on andmete tehingu maksimaalne suurus umbes 140 KBâââviiteks, peaaegu tĂ€pselt Shakespeare'i nĂ€idendi 'Romeo ja Julia' pikkus.â
Loome DAO jÀrgmiste tingimustega:
Kuna startup peab rahastust saama, vajab ta getFunds() toetust vĂ€hemalt 2 osalejalt â DAO investorilt. VĂ€ljastada saab tĂ€pselt nii palju, kui kokku on mĂ€rgitud hÀÀletamisel DAO omanike poolt.
Teeme 3 tĂŒĂŒpi vĂ”tmeid ja lisame tasakaalu haldamiseks loogika 2 uude funktsiooni: vote ja getFunds:
xxâŠxx_ia = investorid, saadaval saldo (vote, deposit, withdrawal)
xxâŠxx_sv = startupid, hÀÀlte arv (vote, getFunds)
xxâŠxx_sf = startupid, hÀÀlte arv (vote, getFunds)
xxâŠxx = avalik aadress (35 tĂ€hte)
Pange tÀhele, et Vote'is pidi me uuendama kohe mitu vÀlja:
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),WriteSet vĂ”imaldab meil teha mitu kirjet ĂŒhe invokeScript tehingu raames.
Nii see vÀlja nÀeb DAO dApp'i vÔtme-vÀli andmemÀlus, pÀrast seda, kui Bob ja Cooper on tÀiendatud ia-deposiid:

Meie sissemakse funktsioon on veidi muutunud:

NĂŒĂŒd jĂ”uab kĂ€tte kĂ”ige olulisem hetk DAO tegevuses â hÀÀletamine projektide ĂŒle rahastamiseks.
Bob hÀÀletab projekti Neli poolt 500000 wavelet'i eest:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
Andmehoidlas nÀeme kÔiki vajalikke kirjeid aadressi Neli jaoks:

Cooper hÀÀletas ka Neli projekti poolt.

Vaatame funktsiooni koodi getFunds. Neli peab koguma vÀhemalt 2 hÀÀlt, et saada vÔimalus vahendeid DAO-st vÀlja vÔtta.

Neli kavatseb vÀlja vÔtta poole talle usaldatud summast:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))
Tal Ônnestub see, see tÀhendab, et DAO töötab!
Me kÀsitlesime DAO loomise protsessi keeles RIDE4DAPPS.
JÀrgnevates osades kÀsitleme koodi refaktoreerimist ja testimiskeskeid.
Koodi tÀisversioon
# 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
}
}
Allikas: habr.com
