Učenje kako napisati Waves pametne ugovore na RIDE i RIDE4DAPPS. 2. dio (DAO - decentralizirana autonomna organizacija)

Učenje kako napisati Waves pametne ugovore na RIDE i RIDE4DAPPS. 2. dio (DAO - decentralizirana autonomna organizacija)

Pozdrav!

В prvi dijelu, detaljno smo ispitali kako stvoriti i raditi s dApp (decentraliziranom aplikacijom) u Valovi RIDE IDE.

Idemo sada malo testirati rastavljeno primjer.

Faza 3. Testiranje dApp računa

Učenje kako napisati Waves pametne ugovore na RIDE i RIDE4DAPPS. 2. dio (DAO - decentralizirana autonomna organizacija)

Kakvi problemi odmah hrle na glasove s Alice dApp Račun?
Prvo:
Boob i Cooper mogu slučajno poslati sredstva na dApp adresu koristeći normalnu Transfer transakcije i stoga im neće moći pristupiti natrag.

Drugo:
Ni na koji način ne ograničavamo Alice u povlačenju sredstava bez pristanka Booba i/ili Coopera. Budući da će, obratite pozornost na provjeru, sve transakcije od Alice biti izvršene.

Popravimo 2 banovanjem Alice Transfer transakcije. Implementirajte ispravljenu skriptu:
Učenje kako napisati Waves pametne ugovore na RIDE i RIDE4DAPPS. 2. dio (DAO - decentralizirana autonomna organizacija)

Pokušavamo povući kovanice s dApp Alice i njezinim potpisom. Dobivamo pogrešku:
Učenje kako napisati Waves pametne ugovore na RIDE i RIDE4DAPPS. 2. dio (DAO - decentralizirana autonomna organizacija)

Pokušaj povlačenja putem povlačenja:

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

Scenarij radi i skužili smo 2. točku!

Faza 4. Kreirajte DAO s glasanjem

Nažalost, jezik RIDE još ne pruža mogućnost rada s kolekcijama (rječnici, rječnici, iteratori, reduktori itd.). Međutim, za sve operacije na ravnim zbirkama ključ-vrijednost možemo dizajnirati sustav za rad sa stringovima, odnosno ključevima i njihovim dešifriranjem.

Stringovi se vrlo lako spajaju, stringovi se mogu odvojiti indeksima.
Prikupimo i raščlanimo niz kao testni slučaj i provjerimo kako će to utjecati na ishod transakcije.
Složili smo se s činjenicom da Alice ne može potpisati Transfer transakciju, jer je ta mogućnost bila blokirana u @verifier za ovu vrstu transakcije.

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

RIDE Žice

Transakcija opet moguća, znamo raditi sa stringovima.
Učenje kako napisati Waves pametne ugovore na RIDE i RIDE4DAPPS. 2. dio (DAO - decentralizirana autonomna organizacija)


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

Podatkovne transakcije

Podatkovne transakcije:
“Maksimalna veličina ključa je 100 znakova, a ključ može sadržavati proizvoljne Unicode kodne točke uključujući razmake i druge simbole koji se ne mogu ispisati. Vrijednosti niza imaju ograničenje od 32,768 bajtova, a maksimalan broj mogućih unosa u podatkovnoj transakciji je 100. Sveukupno, maksimalna veličina podatkovne transakcije je oko 140 kb — za referencu, gotovo točno koliko traje Shakespeareova drama 'Romeo i Julija' '.”

Stvaramo DAO uz sljedeće uvjete:
Kako bi startup dobio sredstva pozivom getFunds() potrebna je podrška od najmanje 2 sudionika - DAO investitora. povući bit će moguće točno onoliko koliko je zbroj naznačen na glasovanje Vlasnici DAO-a.

Napravimo 3 vrste ključeva i dodamo logiku za rad sa bilansima u 2 nove funkcije vote i getFunds:
xx…xx_ia = investitori, raspoloživo stanje (glasovanje, uplata, isplata)
xx…xx_sv = startupi, broj glasova (glasaj, getFunds)
xx…xx_sf = startupi, broj glasova (glasaj, getFunds)
xx…xx = javna adresa (35 znakova)

Obavijest u Voteu da smo morali ažurirati nekoliko polja odjednom:

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

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

Ovako to izgleda u pohrani ključeva i vrijednosti DAO dApp-a nakon što su Bob i Cooper nadopunili ia- depoziti:
Učenje kako napisati Waves pametne ugovore na RIDE i RIDE4DAPPS. 2. dio (DAO - decentralizirana autonomna organizacija)

Naša funkcija depozita se malo promijenila:
Učenje kako napisati Waves pametne ugovore na RIDE i RIDE4DAPPS. 2. dio (DAO - decentralizirana autonomna organizacija)

Sada dolazi najvažniji trenutak u aktivnostima DAO-a - glasanje za projekte za financiranje.

Bob glasa za projekt Neli na 500000 valića:

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

Učenje kako napisati Waves pametne ugovore na RIDE i RIDE4DAPPS. 2. dio (DAO - decentralizirana autonomna organizacija)

U pohrani podataka vidimo sve potrebne unose za Neli adresu:
Učenje kako napisati Waves pametne ugovore na RIDE i RIDE4DAPPS. 2. dio (DAO - decentralizirana autonomna organizacija)
Za projekt Neli glasao je i Cooper.
Učenje kako napisati Waves pametne ugovore na RIDE i RIDE4DAPPS. 2. dio (DAO - decentralizirana autonomna organizacija)

Pogledajmo kod funkcije getFunds. Neli mora skupiti najmanje 2 glasa da bi mogla povući sredstva iz DAO-a.
Učenje kako napisati Waves pametne ugovore na RIDE i RIDE4DAPPS. 2. dio (DAO - decentralizirana autonomna organizacija)

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

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

Učenje kako napisati Waves pametne ugovore na RIDE i RIDE4DAPPS. 2. dio (DAO - decentralizirana autonomna organizacija)

Ona uspijeva, odnosno DAO radi!

Pregledali smo proces stvaranja DAO-a u jeziku RIDE4DAPPS.
U sljedećim dijelovima pobliže ćemo pogledati refaktoriranje koda i testiranje slučajeva.

Potpuni kod 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
Valovi RIDE IDE
Najava programa bespovratnih sredstava

Izvor: www.habr.com

Dodajte komentar