Lær hvordan du skriver Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentralized Autonomous Organization)

Lær hvordan du skriver Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentralized Autonomous Organization)

Hei!

В den første del, har vi undersøkt i detalj hvordan du oppretter og arbeider med en dApp (desentralisert applikasjon) i Waves RIDE IDE.

La oss nå teste det demonterte litt eksempel.

Trinn 3. Testing av dApp-kontoen

Lær hvordan du skriver Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentralized Autonomous Organization)

Hvilke problemer skynder seg umiddelbart til stemmene med Alice Dapp Regnskap?
For det første:
Boob og Cooper kan ved et uhell sende penger til en dApp-adresse ved hjelp av en normal overføre transaksjoner og dermed ikke få tilgang til dem tilbake.

Dernest:
Vi begrenser ikke på noen måte Alice fra å ta ut penger uten samtykke fra Boob og/eller Cooper. Siden, vær oppmerksom på å bekrefte, vil alle transaksjoner fra Alice bli utført.

La oss fikse 2 ved å utestenge Alice overføre transaksjoner. Distribuer det korrigerte skriptet:
Lær hvordan du skriver Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentralized Autonomous Organization)

Vi prøver å ta ut mynter med dApp Alice og signaturen hennes. Vi får en feilmelding:
Lær hvordan du skriver Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentralized Autonomous Organization)

Prøver å trekke ut via uttak:

broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))

Manuset fungerer og vi fant ut det andre punktet!

Trinn 4. Lag en DAO med stemmegivning

Dessverre gir RIDE-språket ennå ikke muligheten til å jobbe med samlinger (ordbøker, ordbøker, iteratorer, reduseringer, etc.). Dog for eventuelle operasjoner på flate samlinger nøkkelverdi vi kan designe et system for arbeid med strenger, henholdsvis med nøkler og deres dekryptering.

Strenger er veldig enkle å sette sammen, strenger kan skilles med indekser.
La oss samle og analysere strengen som et testtilfelle og sjekke hvordan dette vil påvirke resultatet av transaksjonen.
Vi bestemte oss for at Alice ikke kunne signere overføringstransaksjonen, siden denne muligheten ble blokkert i @verifier for denne typen transaksjoner.

La oss øve med strenger og så løse dette.

RIDE strenger

Transaksjonen er mulig igjen, vi vet hvordan vi jobber med strenger.
Lær hvordan du skriver Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentralized Autonomous Organization)


Totalt sett har vi alt du trenger for å skrive kompleks logikk DAO dApp.

Datatransaksjoner

Datatransaksjoner:
"Maksimal størrelse for en nøkkel er 100 tegn, og en nøkkel kan inneholde vilkårlige Unicode-kodepunkter inkludert mellomrom og andre ikke-utskrivbare symboler. Strengeverdier har en grense på 32,768 100 byte og maksimalt antall mulige oppføringer i datatransaksjoner er 140. Totalt sett er den maksimale størrelsen på en datatransaksjon rundt XNUMX kb – for referanse, nesten nøyaktig lengden på Shakespeares skuespill 'Romeo and Juliet' '."

Vi oppretter en DAO med følgende betingelser:
For at en startup skal få finansiering ved å ringe getFunds() støtte fra minst 2 deltakere - DAO-investorer kreves. Ta ut det vil være mulig nøyaktig så mye som summen angitt på stemmegivning DAO-eiere.

La oss lage 3 typer nøkler og legge til logikk for arbeid med saldoer i 2 nye funksjoner vote and getFunds:
xx…xx_ia = investorer, tilgjengelig saldo (stemme, innskudd, uttak)
xx…xx_sv = startups, antall stemmer (stemme, getFunds)
xx…xx_sf = startups, antall stemmer (stemme, getFunds)
xx…xx = offentlig adresse (35 tegn)

Merknad i Vote vi trengte å oppdatere flere felt samtidig:

WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),

WriteSet lar oss lage flere poster samtidig i én invokeScript transaksjoner.

Slik ser det ut i nøkkelverdilageret til DAO dApp etter at Bob og Cooper fylte på ia- innskudd:
Lær hvordan du skriver Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentralized Autonomous Organization)

Innskuddsfunksjonen vår har endret seg litt:
Lær hvordan du skriver Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentralized Autonomous Organization)

Nå kommer det viktigste øyeblikket i DAOs aktiviteter - stemme for prosjekter for finansiering.

Bob stemmer for Neli-prosjektet på 500000 XNUMX wavelets:

broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))

Lær hvordan du skriver Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentralized Autonomous Organization)

I datalageret ser vi alle nødvendige oppføringer for Neli-adressen:
Lær hvordan du skriver Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentralized Autonomous Organization)
Cooper stemte også for Neli-prosjektet.
Lær hvordan du skriver Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentralized Autonomous Organization)

La oss ta en titt på funksjonskoden getFunds. Neli må samle minst 2 stemmer for å kunne ta ut midler fra DAO.
Lær hvordan du skriver Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentralized Autonomous Organization)

Neli kommer til å ta ut halvparten av beløpet som er betrodd henne:

broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))

Lær hvordan du skriver Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentralized Autonomous Organization)

Hun lykkes, det vil si at DAO fungerer!

Vi gjennomgikk prosessen med å lage en DAO på språket RIDE4DAPPS.
I de følgende delene skal vi se nærmere på koderefaktorering og casetesting.

Full kode inn 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
    }
}

Den første delen
Kode på github
Waves RIDE IDE
Kunngjøring av tilskuddsprogram

Kilde: www.habr.com

Legg til en kommentar