Lær at skrive Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentraliseret Autonom Organisation)

Lær at skrive Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentraliseret Autonom Organisation)

Hej alle!

В den første del kiggede vi i detaljer på, hvordan man opretter og arbejder med dApp (decentral applikation) i Waves RIDE IDE.

Lad os teste den adskilte lidt nu eksempel.

Trin 3. Test af dApp-kontoen

Lær at skrive Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentraliseret Autonom Organisation)

Hvilke problemer springer dig straks i øjnene med Alice? DAI Konto?
For det første:
Boob og Cooper kan ved et uheld sende penge til dApp-adressen ved hjælp af almindelig overførsel transaktioner og dermed ikke vil kunne få adgang til dem tilbage.

For det andet:
Vi begrænser på ingen måde Alice i at hæve penge uden Boobs og/eller Coopers godkendelse. Da, vær opmærksom på at verificere, vil alle transaktioner fra Alice blive udført.

Lad os rette 2. ved at forbyde Alice overførsel transaktioner. Lad os implementere det rettede script:
Lær at skrive Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentraliseret Autonom Organisation)

Vi forsøger at trække mønter tilbage fra dApp Alice og hendes signatur. Vi får en fejl:
Lær at skrive Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentraliseret Autonom Organisation)

Lad os prøve at trække tilbage via tilbagetrækning:

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

Scriptet virker, og vi fandt ud af det 2. punkt!

Trin 4. Opret en DAO med afstemning

Desværre giver RIDE-sproget endnu ikke mulighed for at arbejde med samlinger (ordbogsordbøger, iteratorer, reduktionsmidler osv.). Dog til enhver operation med flade samlinger nøgleværdi vi kan designe et system til at arbejde med strenge, i overensstemmelse hermed med nøgler og deres dekryptering.

Strenge er meget nemme at sammenkæde; strenge kan adskilles af indekser.
Lad os samle og analysere en streng som et testeksempel og kontrollere, hvordan dette påvirker resultatet af transaktionen.
Vi slog os fast på det faktum, at Alice ikke kunne underskrive overførselstransaktionen, da denne mulighed var blokeret i @verifier for denne type transaktion.

Lad os øve os med strenge og så løse dette.

RIDE Strings

Transaktionen er mulig igen, vi ved, hvordan man arbejder med strenge.
Lær at skrive Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentraliseret Autonom Organisation)


I alt har vi alt det nødvendige for at skrive kompleks logik DAO dApp.

Datatransaktioner

Datatransaktioner:
"Den maksimale størrelse for en nøgle er 100 tegn, og en nøgle kan indeholde vilkårlige Unicode-kodepunkter inklusive mellemrum og andre ikke-udskrivbare symboler. Strengværdier har en grænse på 32,768 bytes, og det maksimale antal mulige indtastninger i datatransaktionen er 100. Samlet set er den maksimale størrelse af en datatransaktion omkring 140 kb - til reference, næsten nøjagtig længden af ​​Shakespeares skuespil 'Romeo and Juliet' '."

Vi opretter en DAO med følgende betingelser:
For at en startup kan modtage finansiering ved at ringe getFunds() støtte fra mindst 2 deltagere - DAO-investorer - er påkrævet. trække det vil være muligt nøjagtigt så meget som totalen angivet på afstemning DAO ejere.

Lad os lave 3 typer nøgler og tilføje logik til at arbejde med saldi i 2 nye funktioner vote and getFunds:
xx…xx_ia = investorer, disponibel saldo (stemme, indskud, udbetaling)
xx…xx_sv = startups, antal stemmer (stem, getFunds)
xx…xx_sf = startups, antal stemmer (stem, getFunds)
xx…xx = offentlig adresse (35 tegn)

Bemærk venligst, at i afstemningen var vi nødt til at opdatere flere felter på én gang:

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

WriteSet giver os mulighed for at lave flere poster på én gang inden for én invokeScript transaktioner.

Sådan ser det ud i nøgleværdilageret i DAO dApp, efter at Bob og Cooper genopfyldte ia-indskud:
Lær at skrive Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentraliseret Autonom Organisation)

Vores indbetalingsfunktion er ændret lidt:
Lær at skrive Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentraliseret Autonom Organisation)

Nu kommer det vigtigste øjeblik i DAO's aktiviteter - stemme for projekter, der skal finansieres.

Bob stemmer på Nelis 500000 wavelets-projekt:

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

Lær at skrive Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentraliseret Autonom Organisation)

I datalageret ser vi alle de nødvendige indtastninger til Nelis adresse:
Lær at skrive Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentraliseret Autonom Organisation)
Cooper stemte også for Neli-projektet.
Lær at skrive Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentraliseret Autonom Organisation)

Lad os tage et kig på funktionskoden getFunds. Neli skal indsamle minimum 2 stemmer for at kunne hæve midler fra DAO.
Lær at skrive Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentraliseret Autonom Organisation)

Neli vil hæve halvdelen af ​​det beløb, hun har fået betroet:

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

Lær at skrive Waves smarte kontrakter på RIDE og RIDE4DAPPS. Del 2 (DAO - Decentraliseret Autonom Organisation)

Hun lykkes, det vil sige, DAO virker!

Vi så på processen med at skabe en DAO på sproget RIDE4DAPPS.
I de følgende dele vil vi se nærmere på kode refactoring og case test.

Fuld version af koden i 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 del
Kode på GitHub
Waves RIDE IDE
Offentliggørelse af bevillingsprogrammet

Kilde: www.habr.com

Tilføj en kommentar