Õppige kirjutama Waves'i nutikaid lepinguid rakendustes RIDE ja RIDE4DAPPS. 2. osa (DAO – detsentraliseeritud autonoomne organisatsioon)

Õppige kirjutama Waves'i nutikaid lepinguid rakendustes RIDE ja RIDE4DAPPS. 2. osa (DAO – detsentraliseeritud autonoomne organisatsioon)

Tere kõigile!

В esimene osas oleme üksikasjalikult uurinud, kuidas luua dAppi (detsentraliseeritud rakendus) ja sellega töötada Waves RIDE IDE.

Katsetame nüüd lahtivõetut veidi näide.

3. etapp. dApp konto testimine

Õppige kirjutama Waves'i nutikaid lepinguid rakendustes RIDE ja RIDE4DAPPS. 2. osa (DAO – detsentraliseeritud autonoomne organisatsioon)

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:
Õppige kirjutama Waves'i nutikaid lepinguid rakendustes RIDE ja RIDE4DAPPS. 2. osa (DAO – detsentraliseeritud autonoomne organisatsioon)

Püüame välja võtta dApp Alice'i ja tema allkirjaga münte. Saame veateate:
Õppige kirjutama Waves'i nutikaid lepinguid rakendustes RIDE ja RIDE4DAPPS. 2. osa (DAO – detsentraliseeritud autonoomne organisatsioon)

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.
Õppige kirjutama Waves'i nutikaid lepinguid rakendustes RIDE ja RIDE4DAPPS. 2. osa (DAO – detsentraliseeritud autonoomne organisatsioon)


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:
Õppige kirjutama Waves'i nutikaid lepinguid rakendustes RIDE ja RIDE4DAPPS. 2. osa (DAO – detsentraliseeritud autonoomne organisatsioon)

Meie sissemaksefunktsioon on veidi muutunud:
Õppige kirjutama Waves'i nutikaid lepinguid rakendustes RIDE ja RIDE4DAPPS. 2. osa (DAO – detsentraliseeritud autonoomne organisatsioon)

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: []}))

Õppige kirjutama Waves'i nutikaid lepinguid rakendustes RIDE ja RIDE4DAPPS. 2. osa (DAO – detsentraliseeritud autonoomne organisatsioon)

Andmesalves näeme kõiki vajalikke Neli aadressi kirjeid:
Õppige kirjutama Waves'i nutikaid lepinguid rakendustes RIDE ja RIDE4DAPPS. 2. osa (DAO – detsentraliseeritud autonoomne organisatsioon)
Cooper hääletas ka Neli projekti poolt.
Õppige kirjutama Waves'i nutikaid lepinguid rakendustes RIDE ja RIDE4DAPPS. 2. osa (DAO – detsentraliseeritud autonoomne organisatsioon)

Vaatame funktsiooni koodi hankige rahalisi vahendeid. Neli peab koguma vähemalt 2 häält, et saaks DAO-st raha välja võtta.
Õppige kirjutama Waves'i nutikaid lepinguid rakendustes RIDE ja RIDE4DAPPS. 2. osa (DAO – detsentraliseeritud autonoomne organisatsioon)

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: []}))

Õppige kirjutama Waves'i nutikaid lepinguid rakendustes RIDE ja RIDE4DAPPS. 2. osa (DAO – detsentraliseeritud autonoomne organisatsioon)

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 Waves RIDE IDE:

# 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
    }
}

Esimene osa
Kood githubis
Waves RIDE IDE
Toetusprogrammi teadaanne

Allikas: www.habr.com

Lisa kommentaar