Leren Waves slimme contracten schrijven op RIDE en RIDE4DAPPS. Deel 2 (DAO - Gedecentraliseerde Autonome Organisatie)

Leren Waves slimme contracten schrijven op RIDE en RIDE4DAPPS. Deel 2 (DAO - Gedecentraliseerde Autonome Organisatie)

Hallo iedereen!

В eerste deel hebben we in detail gekeken hoe je dApp (gedecentraliseerde applicatie) kunt maken en ermee kunt werken Golven RIDE IDE.

Laten we de gedemonteerde nu een beetje testen voorbeeld.

Fase 3. Het dApp-account testen

Leren Waves slimme contracten schrijven op RIDE en RIDE4DAPPS. Deel 2 (DAO - Gedecentraliseerde Autonome Organisatie)

Welke problemen vallen je meteen op met Alice? dapper Account?
Во-первых:
Boob en Cooper kunnen per ongeluk geld naar het dApp-adres sturen via regulier overdracht transacties en zullen er dus geen toegang toe hebben.

Во-вторых:
We beperken Alice op geen enkele manier in het opnemen van geld zonder de goedkeuring van Boob en/of Cooper. Let op: alle transacties van Alice worden uitgevoerd.

Laten we het tweede probleem oplossen door Alice te verbannen overdracht transacties. Laten we het gecorrigeerde script implementeren:
Leren Waves slimme contracten schrijven op RIDE en RIDE4DAPPS. Deel 2 (DAO - Gedecentraliseerde Autonome Organisatie)

We proberen munten van dApp Alice en haar handtekening op te nemen. We krijgen een foutmelding:
Leren Waves slimme contracten schrijven op RIDE en RIDE4DAPPS. Deel 2 (DAO - Gedecentraliseerde Autonome Organisatie)

Laten we proberen op te nemen via intrekken:

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

Het script werkt en we hebben het tweede punt ontdekt!

Fase 4. Creëer een DAO met stemming

Helaas biedt de RIDE-taal nog niet de mogelijkheid om met verzamelingen te werken (woordenboeken, iterators, reducers, enz.). Echter, voor alle operaties met platte collecties sleutel waarde we kunnen een systeem ontwerpen voor het werken met strings, dus met sleutels en hun decodering.

Tekenreeksen zijn heel gemakkelijk samen te voegen; tekenreeksen kunnen worden gescheiden door indexen.
Laten we een string verzamelen en parseren als testvoorbeeld en controleren hoe dit de uitkomst van de transactie beïnvloedt.
We kwamen tot de conclusie dat Alice de overdrachtstransactie niet kon ondertekenen, omdat deze mogelijkheid voor dit type transactie in @verifier was geblokkeerd.

Laten we oefenen met snaren en dit dan oplossen.

RIDE-snaren

De transactie is weer mogelijk, wij weten hoe we met strings moeten werken.
Leren Waves slimme contracten schrijven op RIDE en RIDE4DAPPS. Deel 2 (DAO - Gedecentraliseerde Autonome Organisatie)


In totaal hebben we alles wat nodig is om complexe logica te schrijven DAO dApp.

Gegevenstransacties

Gegevenstransacties:
“De maximale grootte voor een sleutel is 100 tekens, en een sleutel kan willekeurige Unicode-codepunten bevatten, inclusief spaties en andere niet-afdrukbare symbolen. Tekenreekswaarden hebben een limiet van 32,768 bytes en het maximale aantal mogelijke vermeldingen bij datatransacties is 100. In totaal bedraagt ​​de maximale grootte van een datatransactie ongeveer 140 kb – ter referentie: vrijwel precies de lengte van Shakespeares toneelstuk 'Romeo en Julia'. '. ”

We creëren een DAO met de volgende voorwaarden:
Zodat een startup financiering kan ontvangen door te bellen getFunds() de steun van minimaal 2 deelnemers – DAO-investeerders – is vereist. terugtrekken het zal precies zoveel mogelijk zijn als het totaal aangegeven op stemmen DAO-eigenaren.

Laten we 3 soorten sleutels maken en logica toevoegen voor het werken met saldi in 2 nieuwe functies stemmen en geld ophalen:
xx...xx_IA = investeerders, beschikbaar saldo (stemming, storting, terugtrekking)
xx...xx_sv = startups, aantal stemmen (stemmen, getFunds)
xx...xx_sf = startups, aantal stemmen (stemmen, getFunds)
xx…xx = openbaar adres (35 tekens)

Houd er rekening mee dat we bij Stemmen meerdere velden tegelijk moesten bijwerken:

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

Met WriteSet kunnen we binnen één record meerdere records tegelijk maken invokeScript transacties.

Zo ziet het eruit in de sleutelwaardeopslag van de DAO dApp, nadat Bob en Cooper hebben aangevuld ia-stortingen:
Leren Waves slimme contracten schrijven op RIDE en RIDE4DAPPS. Deel 2 (DAO - Gedecentraliseerde Autonome Organisatie)

Onze stortingsfunctie is enigszins veranderd:
Leren Waves slimme contracten schrijven op RIDE en RIDE4DAPPS. Deel 2 (DAO - Gedecentraliseerde Autonome Organisatie)

Nu komt het belangrijkste moment in de activiteiten van de DAO: stemmen voor te financieren projecten.

Bob stemt voor Neli's 500000 wavelets-project:

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

Leren Waves slimme contracten schrijven op RIDE en RIDE4DAPPS. Deel 2 (DAO - Gedecentraliseerde Autonome Organisatie)

In de gegevensopslag zien we alle benodigde gegevens voor Neli's adres:
Leren Waves slimme contracten schrijven op RIDE en RIDE4DAPPS. Deel 2 (DAO - Gedecentraliseerde Autonome Organisatie)
Cooper stemde ook voor het Neli-project.
Leren Waves slimme contracten schrijven op RIDE en RIDE4DAPPS. Deel 2 (DAO - Gedecentraliseerde Autonome Organisatie)

Laten we eens kijken naar de functiecode krijg fondsen. Neli moet minimaal 2 stemmen verzamelen om geld van de DAO te kunnen opnemen.
Leren Waves slimme contracten schrijven op RIDE en RIDE4DAPPS. Deel 2 (DAO - Gedecentraliseerde Autonome Organisatie)

Neli gaat de helft van het haar toevertrouwde bedrag opnemen:

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

Leren Waves slimme contracten schrijven op RIDE en RIDE4DAPPS. Deel 2 (DAO - Gedecentraliseerde Autonome Organisatie)

Het lukt haar, dat wil zeggen, DAO werkt!

We hebben gekeken naar het proces van het maken van een DAO in de taal RIDE4DAPPS.
In de volgende delen gaan we dieper in op coderefactoring en case-testen.

Volledige versie van de code in Golven 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
    }
}

Het eerste deel
Codeer op GitHub
Golven RIDE IDE
Bekendmaking van het subsidieprogramma

Bron: www.habr.com

Voeg een reactie