Învățați să scrieți contracte inteligente Waves pe RIDE și RIDE4DAPPS. Partea 2 (DAO - Organizație autonomă descentralizată)

Învățați să scrieți contracte inteligente Waves pe RIDE și RIDE4DAPPS. Partea 2 (DAO - Organizație autonomă descentralizată)

Bună ziua tuturor!

В primul partea în care am analizat în detaliu cum să creați și să lucrați cu dApp (aplicație descentralizată) în Waves RIDE IDE.

Să-l testăm puțin pe cel dezasamblat acum exemplu.

Etapa 3. Testarea contului dApp

Învățați să scrieți contracte inteligente Waves pe RIDE și RIDE4DAPPS. Partea 2 (DAO - Organizație autonomă descentralizată)

Ce probleme iti sar imediat in fata cu Alice? Dapp Cont?
În primul rând:
Boob și Cooper pot trimite accidental fonduri la adresa dApp folosind obișnuit transfer tranzacții și astfel nu le va putea accesa înapoi.

În al doilea rând:
Nu restricționăm în niciun fel pe Alice să retragă fonduri fără aprobarea lui Boob și/sau Cooper. Deoarece, acordați atenție verificării, toate tranzacțiile de la Alice vor fi executate.

Să rezolvăm locul 2 interzicând-o pe Alice transfer tranzacții. Să implementăm scriptul corectat:
Învățați să scrieți contracte inteligente Waves pe RIDE și RIDE4DAPPS. Partea 2 (DAO - Organizație autonomă descentralizată)

Încercăm să retragem monede din dApp Alice și semnătura ei. Primim o eroare:
Învățați să scrieți contracte inteligente Waves pe RIDE și RIDE4DAPPS. Partea 2 (DAO - Organizație autonomă descentralizată)

Să încercăm să retragem prin retragere:

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

Scenariul funcționează și ne-am dat seama de punctul 2!

Etapa 4. Creați un DAO cu vot

Din păcate, limbajul RIDE nu oferă încă capacitatea de a lucra cu colecții (dicționare de dicționare, iteratoare, reductoare etc.). Cu toate acestea, pentru orice operațiuni cu colecții plate valoare cheie putem proiecta un sistem de lucru cu șiruri, în consecință cu chei și decriptarea acestora.

Șirurile sunt foarte ușor de concatenat; șirurile pot fi separate prin indici.
Să colectăm și să analizăm un șir ca exemplu de testare și să verificăm modul în care acesta afectează rezultatul tranzacției.
Am stabilit că Alice nu a putut semna tranzacția de transfer, deoarece această capacitate a fost blocată în @verifier pentru acest tip de tranzacție.

Să exersăm cu șiruri și apoi să rezolvăm asta.

RIDE Corzi

Tranzacția este posibilă din nou, știm să lucrăm cu șiruri.
Învățați să scrieți contracte inteligente Waves pe RIDE și RIDE4DAPPS. Partea 2 (DAO - Organizație autonomă descentralizată)


În total, avem tot ce este necesar pentru a scrie o logică complexă DAO dApp.

Tranzacții de date

Tranzacții de date:
„Dimensiunea maximă pentru o cheie este de 100 de caractere, iar o cheie poate conține puncte de cod Unicode arbitrare, inclusiv spații și alte simboluri care nu pot fi imprimate. Valorile șirurilor au o limită de 32,768 de octeți, iar numărul maxim de intrări posibile în tranzacția de date este de 100. În general, dimensiunea maximă a unei tranzacții de date este de aproximativ 140 kb — pentru referință, aproape exact lungimea piesei lui Shakespeare „Romeo și Julieta”. '.”

Creăm un DAO cu următoarele condiții:
Pentru ca un startup să primească finanțare prin apel getFunds() este necesar sprijinul a cel puțin 2 participanți - investitori DAO. Retrage va fi posibil exact cât totalul indicat pe vot proprietarii DAO.

Să facem 3 tipuri de chei și să adăugăm logica pentru lucrul cu soldurile în 2 funcții noi vote și getFunds:
xx...xx_in absenta = investitori, sold disponibil (vot, depunere, retragere)
xx...xx_sv = startup-uri, număr de voturi (votați, obțineți fonduri)
xx...xx_sf = startup-uri, număr de voturi (votați, obțineți fonduri)
xx…xx = adresa publică (35 de caractere)

Vă rugăm să rețineți că în Vote trebuie să actualizăm mai multe câmpuri simultan:

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

WriteSet ne permite să facem mai multe înregistrări simultan în cadrul uneia invokeScript tranzacții.

Așa arată în stocarea cheie-valoare a DAO dApp, după ce Bob și Cooper s-au alimentat ia-depozite:
Învățați să scrieți contracte inteligente Waves pe RIDE și RIDE4DAPPS. Partea 2 (DAO - Organizație autonomă descentralizată)

Funcția noastră de depozit s-a schimbat ușor:
Învățați să scrieți contracte inteligente Waves pe RIDE și RIDE4DAPPS. Partea 2 (DAO - Organizație autonomă descentralizată)

Acum vine cel mai important moment din activitățile DAO - vot pentru proiectele care urmează să fie finanțate.

Bob votează pentru proiectul 500000 de wavelets al lui Neli:

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

Învățați să scrieți contracte inteligente Waves pe RIDE și RIDE4DAPPS. Partea 2 (DAO - Organizație autonomă descentralizată)

În depozitul de date vedem toate înregistrările necesare pentru adresa lui Neli:
Învățați să scrieți contracte inteligente Waves pe RIDE și RIDE4DAPPS. Partea 2 (DAO - Organizație autonomă descentralizată)
Cooper a votat și pentru proiectul Neli.
Învățați să scrieți contracte inteligente Waves pe RIDE și RIDE4DAPPS. Partea 2 (DAO - Organizație autonomă descentralizată)

Să aruncăm o privire la codul funcției getFunds. Neli trebuie să adune minim 2 voturi pentru a putea retrage fonduri din DAO.
Învățați să scrieți contracte inteligente Waves pe RIDE și RIDE4DAPPS. Partea 2 (DAO - Organizație autonomă descentralizată)

Neli urmează să retragă jumătate din suma care i-a fost încredințată:

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

Învățați să scrieți contracte inteligente Waves pe RIDE și RIDE4DAPPS. Partea 2 (DAO - Organizație autonomă descentralizată)

Ea reușește, adică DAO funcționează!

Ne-am uitat la procesul de creare a unui DAO în limbă RIDE4DAPPS.
În următoarele părți, vom arunca o privire mai atentă asupra refactorizării codului și testării cazului.

Versiunea completă a codului în 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
    }
}

Prima parte
Cod pe GitHub
Waves RIDE IDE
Anunțul programului de grant

Sursa: www.habr.com

Adauga un comentariu