Tere kõigile!
В
Katsetame nüüd lahtivõetut veidi
3. etapp. dApp konto testimine
Millised probleemid tormavad Alice'iga kohe häält dApp Konto?
Esiteks:
Boob ja Cooper võivad tavalist aadressi kasutades kogemata raha dApp-i aadressile saata üle tehinguid ega pääse seetõttu neile tagasi.Teiseks:
Me ei piira mingil viisil Alice'i raha väljavõtmist ilma Boobi ja/või Cooperi nõusolekuta. Kuna kontrollimiseks pöörake tähelepanu, sooritatakse kõik Alice'i tehingud.
Parandame 2, keelates Alice'i üle tehingud. Juurutage parandatud skript:

Püüame välja võtta dApp Alice'i ja tema allkirjaga münte. Saame veateate:
Proovin välja võtta väljavõtmise teel:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))
Stsenaarium töötab ja saime 2. punkti välja!
4. etapp. Looge hääletamisega DAO
Kahjuks ei anna RIDE keel veel võimalust kogudega (sõnastikud, sõnastikud, iteraatorid, redutseerijad jne) töötada. Kuid mis tahes toimingute jaoks korterkollektsioonides võtmeväärtus saame kujundada süsteemi stringidega töötamiseks, vastavalt võtmete ja nende dekrüpteerimiseks.
Stringe on väga lihtne ühendada, stringe saab eraldada indeksitega.
Kogume ja analüüsime stringi testjuhtumina ning kontrollime, kuidas see tehingu tulemust mõjutab.
Leppisime sellega, et Alice ei saanud ülekandetehingule alla kirjutada, kuna see võimalus oli @verifier seda tüüpi tehingu puhul blokeeritud.
Harjutame paeltega ja siis lahendame ära.
RIDE Stringid
Tehing on taas võimalik, oskame stringidega töötada.

Kokku on meil kõik, mida vajate keeruka loogika kirjutamiseks DAO dApp.
Andmetehingud
Andmetehingud:
"Võtme maksimaalne suurus on 100 tähemärki ja võti võib sisaldada suvalisi Unicode'i koodipunkte, sealhulgas tühikuid ja muid mitteprinditavaid sümboleid. Stringi väärtuste limiit on 32,768 100 baiti ja maksimaalne võimalike kirjete arv andmetehingus on 140. Üldiselt on andmetehingu maksimaalne suurus umbes XNUMX kb – võrdluseks peaaegu täpselt sama pikk kui Shakespeare'i näidend "Romeo ja Julia" '.
Loome DAO järgmistel tingimustel:
Selleks, et startup saaks rahastuse helistades hankige raha () vajalik on vähemalt 2 osaleja toetus – DAO investorid. Väljund see on võimalik täpselt nii palju kui näidatud summa hääletamine DAO omanikud.
Teeme 3 tüüpi võtmeid ja lisame loogika saldodega töötamiseks kahes uues funktsioonis hääl ja getFunds:
xx…xx_ia = investorid, vaba saldo (hääletus, sissemakse, väljamakse)
xx…xx_sv = startupid, häälte arv (hääletage, hankige raha)
xx…xx_sf = startupid, häälte arv (hääletage, hankige raha)
xx…xx = avalik aadress (35 tähemärki)
Hääletuse teade, et pidime värskendama mitut välja korraga:
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),
WriteSet võimaldab meil teha mitu kirjet korraga ühes invokeScript tehingud.
Nii näeb see välja DAO dAppi võtmeväärtuste poes pärast Bobi ja Cooperi täiendamist ia- hoiused:
Meie sissemaksefunktsioon on veidi muutunud:
Nüüd tuleb DAO tegevuse kõige olulisem hetk - hääletama projektide rahastamiseks.
Bob hääletab Neli projekti poolt 500000 XNUMX lainel:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
Andmesalves näeme kõiki vajalikke Neli aadressi kirjeid:
Cooper hääletas ka Neli projekti poolt.
Vaatame funktsiooni koodi hankige rahalisi vahendeid. Neli peab koguma vähemalt 2 häält, et saaks DAO-st raha välja võtta.
Neli võtab poole talle usaldatud summast välja:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))
Tal õnnestub, see tähendab, et DAO töötab!
Vaatasime üle DAO loomise protsessi keeles RIDE4DAPPS.
Järgmistes osades vaatleme lähemalt koodi ümberkujundamist ja juhtumite testimist.
Täielik kood sisse
# 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: www.habr.com