Učenje pisanja Waves pametnih ugovora na RIDE i RIDE4DAPPS. Dio 2 (DAO - Decentralizirana autonomna organizacija)

Učenje pisanja Waves pametnih ugovora na RIDE i RIDE4DAPPS. Dio 2 (DAO - Decentralizirana autonomna organizacija)

Pozdrav svima!

В prvi dijelu smo detaljno pogledali kako kreirati i raditi s dApp-om (decentralizirana aplikacija) u Waves RIDE IDE.

Hajde da sada malo testiramo rastavljenu primer.

Faza 3. Testiranje dApp naloga

Učenje pisanja Waves pametnih ugovora na RIDE i RIDE4DAPPS. Dio 2 (DAO - Decentralizirana autonomna organizacija)

Koji problemi vam odmah napadaju s Alisom? dApp Račun?
Prvo:
Boob i Cooper mogu slučajno poslati sredstva na dApp adresu koristeći regularnu transfer transakcije i stoga im neće moći pristupiti nazad.

Drugo:
Ne ograničavamo Alice ni na koji način u povlačenju sredstava bez odobrenja Boob-a i/ili Coopera. Pošto, obratite pažnju na verifikaciju, sve transakcije od Alice će biti izvršene.

Popravimo 2. banovanjem Alice transfer transakcije. Hajde da primenimo ispravljenu skriptu:
Učenje pisanja Waves pametnih ugovora na RIDE i RIDE4DAPPS. Dio 2 (DAO - Decentralizirana autonomna organizacija)

Pokušavamo povući novčiće iz dApp Alice i njen potpis. Dobijamo grešku:
Učenje pisanja Waves pametnih ugovora na RIDE i RIDE4DAPPS. Dio 2 (DAO - Decentralizirana autonomna organizacija)

Pokušajmo se povući putem povlačenja:

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

Scenarij radi i shvatili smo 2. tačku!

Faza 4. Kreirajte DAO sa glasanjem

Nažalost, jezik RIDE još uvijek ne pruža mogućnost rada sa kolekcijama (rječnici, iteratori, reduktori, itd.). Međutim, za sve operacije sa ravnim kolekcijama ključ-vrijednost možemo dizajnirati sistem za rad sa stringovima, u skladu sa ključevima i njihovom dešifrovanjem.

Stringove je vrlo lako spojiti;
Hajde da prikupimo i raščlanimo string kao testni primer i proverimo kako to utiče na ishod transakcije.
Sredili smo se na činjenici da Alice nije mogla potpisati Transfer transakciju, jer je ova mogućnost blokirana u @verifikatoru za ovu vrstu transakcije.

Vježbajmo sa žicama i onda riješimo ovo.

RIDE Strings

Transakcija je opet moguća, znamo raditi sa stringovima.
Učenje pisanja Waves pametnih ugovora na RIDE i RIDE4DAPPS. Dio 2 (DAO - Decentralizirana autonomna organizacija)


Ukupno imamo sve što je potrebno za pisanje složene logike DAO dApp.

Transakcije podataka

Transakcije podataka:
„Maksimalna veličina ključa je 100 znakova, a ključ može sadržavati proizvoljne Unicode kodne tačke uključujući razmake i druge simbole koji se ne mogu ispisati. Vrijednosti nizova imaju ograničenje od 32,768 bajtova, a maksimalni broj mogućih unosa u transakciji podataka je 100. Sveukupno, maksimalna veličina transakcije podataka je oko 140 kb — za referencu, skoro tačno koliko traje Shakespeareova drama 'Romeo i Julija '.

Mi kreiramo DAO sa sledećim uslovima:
Kako bi startup dobio sredstva pozivom getFunds() potrebna je podrška najmanje 2 učesnika - DAO investitora. Povuci to će biti moguće tačno onoliko koliko je ukupno navedeno na glasanje DAO vlasnici.

Napravimo 3 vrste ključeva i dodajmo logiku za rad sa stanjem u 2 nove funkcije vote i getFunds:
xx…xx_ia = investitori, raspoloživi bilans (glasanje, depozit, povlačenje)
xx…xx_sv = startupi, broj glasova (glasajte, nabavite sredstva)
xx…xx_sf = startupi, broj glasova (glasajte, nabavite sredstva)
xx…xx = javna adresa (35 znakova)

Napominjemo da smo u Glasanju morali ažurirati nekoliko polja odjednom:

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

WriteSet nam omogućava da napravimo nekoliko zapisa odjednom unutar jednog invokeScript transakcije.

Ovako to izgleda u skladištu ključ/vrijednost DAO dApp, nakon što su Bob i Cooper dopunili ia- depoziti:
Učenje pisanja Waves pametnih ugovora na RIDE i RIDE4DAPPS. Dio 2 (DAO - Decentralizirana autonomna organizacija)

Naša funkcija depozita je malo promijenjena:
Učenje pisanja Waves pametnih ugovora na RIDE i RIDE4DAPPS. Dio 2 (DAO - Decentralizirana autonomna organizacija)

Sada dolazi najvažniji trenutak u aktivnostima DAO-a - glasajte za projekte koji će se finansirati.

Bob glasa za Neliin projekat 500000 talasa:

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

Učenje pisanja Waves pametnih ugovora na RIDE i RIDE4DAPPS. Dio 2 (DAO - Decentralizirana autonomna organizacija)

U skladištu podataka vidimo sve potrebne unose za Nelinu adresu:
Učenje pisanja Waves pametnih ugovora na RIDE i RIDE4DAPPS. Dio 2 (DAO - Decentralizirana autonomna organizacija)
Cooper je takođe glasao za projekat Neli.
Učenje pisanja Waves pametnih ugovora na RIDE i RIDE4DAPPS. Dio 2 (DAO - Decentralizirana autonomna organizacija)

Pogledajmo kod funkcije getFunds. Neli mora prikupiti minimalno 2 glasa da bi mogla povući sredstva iz DAO-a.
Učenje pisanja Waves pametnih ugovora na RIDE i RIDE4DAPPS. Dio 2 (DAO - Decentralizirana autonomna organizacija)

Neli će podići polovinu iznosa koji joj je poveren:

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

Učenje pisanja Waves pametnih ugovora na RIDE i RIDE4DAPPS. Dio 2 (DAO - Decentralizirana autonomna organizacija)

Ona uspeva, odnosno DAO radi!

Pogledali smo proces stvaranja DAO-a na jeziku RIDE4DAPPS.
U sljedećim dijelovima ćemo detaljnije pogledati refaktoriranje koda i testiranje slučajeva.

Puna verzija koda u 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
    }
}

Prvi dio
Kod na GitHubu
Waves RIDE IDE
Najava grant programa

izvor: www.habr.com

Kupite pouzdan hosting za sajtove sa DDoS zaštitom, VPS VDS servere 🔥 Kupite pouzdan web hosting sa DDoS zaštitom, VPS VDS servere | ProHoster