Lad os lére at skrive Waves smart contracts i RIDE og RIDE4DAPPS. Del 2 (DAO — Decentraliseret Autonom Organisation)

Lad os lére at skrive Waves smart contracts i RIDE og RIDE4DAPPS. Del 2 (DAO — Decentraliseret Autonom Organisation)

Hej alle sammen!

I den fĂžrste I delte grundigt, hvordan man opretter og arbejder med en dApp (decentraliseret applikation) i Waves RIDE IDE.

Lad os nu teste det, vi har gennemgÄet eksempel.

Trin 3. Testning af dApp-kontoen

Lad os lére at skrive Waves smart contracts i RIDE og RIDE4DAPPS. Del 2 (DAO — Decentraliseret Autonom Organisation)

Hvilke problemer dukker straks op med Alice? dApp Konto?
For det fĂžrste:
Boob og Cooper kan utilsigtet sende midler til dApp-adressen via en almindelig overfÞrsel transaktion og derved ikke fÄ adgang til dem igen.

For det andet:
Vi begrĂŠnser ikke Alice i at hĂŠve midler uden aftale med Boob eller(og) Cooper. Som bemĂŠrket, vil alle transaktioner fra Alice blive udfĂžrt.

Lad os rette nummer 2 ved at forbyde Alice overfĂžrsel transaktioner. Vi deployer det rettede script:
Lad os lére at skrive Waves smart contracts i RIDE og RIDE4DAPPS. Del 2 (DAO — Decentraliseret Autonom Organisation)
ïżŒ
Vi prÞver at hÊve mÞnter fra dApp med Alice og hendes underskrift. Vi fÄr en fejl:
Lad os lére at skrive Waves smart contracts i RIDE og RIDE4DAPPS. Del 2 (DAO — Decentraliseret Autonom Organisation)

Vi prĂžver at hĂŠve via withdraw:

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

Scriptet fungerer, og vi har styr pÄ punkt 2!

Trin 4. Opretter DAO med afstemning

DesvĂŠrre er der i RIDE-sproget endnu ikke mulighed for at arbejde med samlinger (dictionaries of dictionaries, iterators, reducers osv.). Men for alle operationer med flade samlinger key-value kan vi designe et system til at arbejde med strenge, svarende til nĂžglerne og deres dekodning.

Det er meget nemt at konkatere strenge, og strenge kan deles efter indekser.
Lad os som et testeksempel samle og analysere en streng og se, hvordan det pÄvirker resultatet af transaktionen.
Vi stoppede ved, at Alice ikke kunne underskrive Transfer-transaktionen, da denne mulighed var blokeret i @verifier for denne type transaktioner.

Lad os Þve os lidt med strenge, og sÄ giver vi lov til det.

RIDE Strings

Transaktionen er igen mulig, vi kan arbejde med strenge.
Lad os lére at skrive Waves smart contracts i RIDE og RIDE4DAPPS. Del 2 (DAO — Decentraliseret Autonom Organisation)

ïżŒ
SĂ„ alt i alt har vi det nĂždvendige for at skrive kompleks logik DAO dApp.

Data Transaktioner

Data Transaktioner:
“Den maksimale stĂžrrelse for en nĂžgle er 100 tegn, og en nĂžgle kan indeholde vilkĂ„rlige Unicode-tegn, herunder mellemrum og andre ikke-udskrivelige symboler. StrengvĂŠrdier har en grĂŠnse pĂ„ 32.768 bytes, og det maksimale antal mulige poster i data-transaktionen er 100. Samlet set er den maksimale stĂžrrelse af en data-transaktion cirka 140kb — til reference, nĂŠsten prĂŠcis lĂŠngden af Shakespeares skuespil ‘Romeo og Julie’.”

Opretter DAO med fĂžlgende betingelser:
For at en startup kan fĂ„ finansiering ved at kalde getFunds() er der brug for stĂžtte fra mindst 2 deltagere — DAO-investorer. Udskriv Der kan hĂŠves prĂŠcist det belĂžb, som samlet er angivet til afstemning ejerne af DAO.

Lad os lave 3 typer nĂžgler og tilfĂžje logik til at arbejde med saldi i 2 nye funktioner vote og getFunds:
xx
xx_ia = investorer, tilgéngelig saldo (vote, deposit, withdrawal)
xx
xx_sv = startups, antal stemmer (vote, getFunds)
xx
xx_sf = startups, antal stemmer (vote, getFunds)
xx
xx = offentlig adresse (35 tegn)

BemÊrk, at vi i Vote skal opdatere flere felter pÄ én gang:

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

WriteSet giver os mulighed for at lave flere registreringer inden for én invokeScript transaktion.

SÄdan ser det ud i key-value lagringssystemet DAO dApp, efter at Bob og Cooper har indskudt ia-indskud:
Lad os lére at skrive Waves smart contracts i RIDE og RIDE4DAPPS. Del 2 (DAO — Decentraliseret Autonom Organisation)

Indskudsfunktionen er blevet let ĂŠndret:
Lad os lére at skrive Waves smart contracts i RIDE og RIDE4DAPPS. Del 2 (DAO — Decentraliseret Autonom Organisation)

Nu kommer det vigtigste þjeblik i DAO's aktiviteter — afstemning om projekter til finansiering.

Bob stemmer for projektet Neli med 500000 wavelets:

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

Lad os lére at skrive Waves smart contracts i RIDE og RIDE4DAPPS. Del 2 (DAO — Decentraliseret Autonom Organisation)

I datalageret ser vi alle nĂždvendige optegnelser for adressen Neli:
Lad os lére at skrive Waves smart contracts i RIDE og RIDE4DAPPS. Del 2 (DAO — Decentraliseret Autonom Organisation)
Cooper har ogsÄ stemt for projektet Neli.
Lad os lére at skrive Waves smart contracts i RIDE og RIDE4DAPPS. Del 2 (DAO — Decentraliseret Autonom Organisation)

Lad os se pÄ koden for funktionen getFunds. Neli skal samle mindst 2 stemmer for at kunne trÊkke midler ud af DAO.
Lad os lére at skrive Waves smart contracts i RIDE og RIDE4DAPPS. Del 2 (DAO — Decentraliseret Autonom Organisation)

Neli planlĂŠgger at trĂŠkke halvdelen af det betroede belĂžb:

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

Lad os lére at skrive Waves smart contracts i RIDE og RIDE4DAPPS. Del 2 (DAO — Decentraliseret Autonom Organisation)

Hun lykkes med det, hvilket betyder, at DAO fungerer!

Vi har gennemgÄet processen med at oprette en DAO pÄ sprog RIDE4DAPPS.
I de nĂŠste dele vil vi dykke nĂŠrmere ned i refaktorering af koden og testcases.

Den komplette version af koden findes 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
    }
}

FĂžrste del
Koden pÄ GitHub
Waves RIDE IDE
Annoncering af tilskudsordning

Kilde: habr.com

KĂžb pĂ„lidelig webhosting med DDoS-beskyttelse, VPS VDS-servere đŸ”„ KĂžb pĂ„lidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster