Leer hoe om Waves-slimkontrakte op RIDE en RIDE4DAPPS te skryf. Deel 2 (DAO - Gedesentraliseerde outonome organisasie)

Leer hoe om Waves-slimkontrakte op RIDE en RIDE4DAPPS te skryf. Deel 2 (DAO - Gedesentraliseerde outonome organisasie)

Hallo almal!

В eerste deel, ons het in detail ondersoek hoe om 'n dApp (gedesentraliseerde toepassing) in te skep en daarmee te werk Golwe RIDE IDE.

Kom ons toets nou die gedemonteerde 'n bietjie Byvoorbeeld.

Fase 3. Toets die dApp-rekening

Leer hoe om Waves-slimkontrakte op RIDE en RIDE4DAPPS te skryf. Deel 2 (DAO - Gedesentraliseerde outonome organisasie)

Watter probleme jaag dadelik na die stemme met Alice dApp Rekening?
In die eerste plek:
Boob en Cooper kan per ongeluk fondse na 'n dApp-adres stuur met 'n normale oordra transaksies en sal dus nie weer toegang daartoe kan kry nie.

In die tweede plek:
Ons beperk op geen manier vir Alice om fondse te onttrek sonder die toestemming van Boob en/of Cooper nie. Aangesien, let op om te verifieer, sal alle transaksies van Alice uitgevoer word.

Kom ons maak 2 reg deur Alice te verban oordra transaksies. Ontplooi die gekorrigeerde skrif:
Leer hoe om Waves-slimkontrakte op RIDE en RIDE4DAPPS te skryf. Deel 2 (DAO - Gedesentraliseerde outonome organisasie)

Ons probeer munte met dApp Alice en haar handtekening onttrek. Ons kry 'n fout:
Leer hoe om Waves-slimkontrakte op RIDE en RIDE4DAPPS te skryf. Deel 2 (DAO - Gedesentraliseerde outonome organisasie)

Probeer om te onttrek via onttrekking:

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

Die draaiboek werk en ons het die 2de punt uitgepluis!

Fase 4. Skep 'n DAO met stem

Ongelukkig bied die RIDE-taal nog nie die vermoë om met versamelings (woordeboeke, woordeboeke, iterators, verkleiners, ens.) te werk nie. Maar vir enige operasies op plat versamelings sleutelwaarde ons kan 'n stelsel ontwerp om met stringe te werk, onderskeidelik met sleutels en hul dekripsie.

Strings is baie maklik om aaneen te koppel, stringe kan deur indekse geskei word.
Kom ons versamel en ontleed die string as 'n toetsgeval en kyk hoe dit die uitkoms van die transaksie sal beïnvloed.
Ons het vasgestel op die feit dat Alice nie die oordragtransaksie kon onderteken nie, aangesien hierdie moontlikheid in @verifier vir hierdie tipe transaksie geblokkeer is.

Kom ons oefen met snare en los dit dan op.

RY Snare

Die transaksie is weer moontlik, ons weet hoe om met snare te werk.
Leer hoe om Waves-slimkontrakte op RIDE en RIDE4DAPPS te skryf. Deel 2 (DAO - Gedesentraliseerde outonome organisasie)


In totaal het ons alles wat jy nodig het om komplekse logika te skryf DAO dApp.

Data transaksies

Datatransaksies:
“Die maksimum grootte vir 'n sleutel is 100 karakters, en 'n sleutel kan arbitrêre Unicode-kodepunte bevat, insluitend spasies en ander nie-drukbare simbole. Stringwaardes het 'n limiet van 32,768 100 grepe en die maksimum aantal moontlike inskrywings in datatransaksie is 140. Oor die algemeen is die maksimum grootte van 'n datatransaksie ongeveer XNUMXkb - ter verwysing, byna presies die lengte van Shakespeare se toneelstuk 'Romeo and Juliet' '."

Ons skep 'n DAO met die volgende voorwaardes:
Ten einde vir 'n begin om befondsing te kry deur te bel getFunds() die ondersteuning van ten minste 2 deelnemers - DAO-beleggers word vereis. Onttrek dit sal presies soveel moontlik wees as die som aangedui op stem DAO eienaars.

Kom ons maak 3 tipes sleutels en voeg logika by om met saldo's te werk in 2 nuwe funksies stem en getFunds:
xx…xx_ia = beleggers, beskikbare saldo (stem, deposito, onttrekking)
xx…xx_sv = opstart, aantal stemme (stem, kry Fondse)
xx…xx_sf = opstart, aantal stemme (stem, kry Fondse)
xx…xx = publieke adres (35 karakters)

Kennisgewing in Stem ons moes verskeie velde gelyktydig opdateer:

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

WriteSet stel ons in staat om verskeie rekords gelyktydig binne een te maak invokeScript transaksies.

Dit is hoe dit lyk in die sleutelwaarde-winkel van die DAO dApp nadat Bob en Cooper aangevul het ia- deposito's:
Leer hoe om Waves-slimkontrakte op RIDE en RIDE4DAPPS te skryf. Deel 2 (DAO - Gedesentraliseerde outonome organisasie)

Ons deposito funksie het effens verander:
Leer hoe om Waves-slimkontrakte op RIDE en RIDE4DAPPS te skryf. Deel 2 (DAO - Gedesentraliseerde outonome organisasie)

Nou kom die belangrikste oomblik in die aktiwiteite van die DAO - stem vir projekte vir befondsing.

Bob stem vir die Neli-projek op 500000 XNUMX wavelets:

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

Leer hoe om Waves-slimkontrakte op RIDE en RIDE4DAPPS te skryf. Deel 2 (DAO - Gedesentraliseerde outonome organisasie)

In die datastoor sien ons al die nodige inskrywings vir die Neli-adres:
Leer hoe om Waves-slimkontrakte op RIDE en RIDE4DAPPS te skryf. Deel 2 (DAO - Gedesentraliseerde outonome organisasie)
Cooper het ook vir die Neli-projek gestem.
Leer hoe om Waves-slimkontrakte op RIDE en RIDE4DAPPS te skryf. Deel 2 (DAO - Gedesentraliseerde outonome organisasie)

Kom ons kyk na die funksiekode getFunds. Neli moet ten minste 2 stemme insamel om fondse by die DAO te kan onttrek.
Leer hoe om Waves-slimkontrakte op RIDE en RIDE4DAPPS te skryf. Deel 2 (DAO - Gedesentraliseerde outonome organisasie)

Neli gaan die helfte van die bedrag wat aan haar toevertrou is onttrek:

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

Leer hoe om Waves-slimkontrakte op RIDE en RIDE4DAPPS te skryf. Deel 2 (DAO - Gedesentraliseerde outonome organisasie)

Sy slaag, dit wil sê die DAO werk!

Ons het die proses hersien om 'n DAO in die taal te skep RIDE4DAPPS.
In die volgende dele sal ons 'n nader kyk na kode herfaktorering en gevaltoetsing.

Volle kode in Golwe 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
    }
}

Eerste deel
Kode op github
Golwe RIDE IDE
Aankondiging van die toekenningsprogram

Bron: will.com

Voeg 'n opmerking