Opi kirjoittamaan Waves-älysopimuksia RIDE- ja RIDE4DAPPS-palveluissa. Osa 2 (DAO – Hajautettu autonominen organisaatio)

Opi kirjoittamaan Waves-älysopimuksia RIDE- ja RIDE4DAPPS-palveluissa. Osa 2 (DAO – Hajautettu autonominen organisaatio)

Hei kaikille!

В ensimmäinen osa, olemme tutkineet yksityiskohtaisesti, kuinka luodaan dApp (hajautettu sovellus) ja työskennellä sen kanssa Waves RIDE IDE.

Testataan nyt vähän purettua esimerkki.

Vaihe 3. dApp-tilin testaus

Opi kirjoittamaan Waves-älysopimuksia RIDE- ja RIDE4DAPPS-palveluissa. Osa 2 (DAO – Hajautettu autonominen organisaatio)

Mitkä ongelmat ryntäävät välittömästi ääniin Alicen kanssa DAPP Tili?
Ensiksi:
Boob ja Cooper voivat vahingossa lähettää varoja dApp-osoitteeseen käyttämällä normaalia siirtää liiketoimia, joten he eivät voi käyttää niitä takaisin.

Toiseksi:
Emme millään tavalla rajoita Alicea nostamaan varoja ilman Boobin ja/tai Cooperin lupaa. Koska kiinnitä huomiota tarkistamiseen, kaikki Alice-tapahtumat suoritetaan.

Korjataan 2 kieltämällä Alice siirtää liiketoimia. Ota korjattu komentosarja käyttöön:
Opi kirjoittamaan Waves-älysopimuksia RIDE- ja RIDE4DAPPS-palveluissa. Osa 2 (DAO – Hajautettu autonominen organisaatio)

Yritämme nostaa kolikoita dApp Alicella ja hänen allekirjoituksellaan. Saamme virheilmoituksen:
Opi kirjoittamaan Waves-älysopimuksia RIDE- ja RIDE4DAPPS-palveluissa. Osa 2 (DAO – Hajautettu autonominen organisaatio)

Kotiutuksen yrittäminen noston kautta:

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

Käsikirjoitus toimii ja keksimme toisen kohdan!

Vaihe 4. Luo DAO äänestämällä

Valitettavasti RIDE-kieli ei vielä tarjoa mahdollisuutta työskennellä kokoelmien kanssa (sanakirjat, sanakirjat, iteraattorit, supistimet jne.). Kuitenkin kaikkiin tasakokoelmiin kohdistuviin toimiin avainarvo Voimme suunnitella järjestelmän merkkijonojen, vastaavasti avaimien ja niiden salauksen purkamiseen.

Merkkijonot on erittäin helppo ketjuttaa, merkkijonot voidaan erottaa indekseillä.
Kerätään ja jäsennetään merkkijono testitapauksena ja tarkistetaan kuinka tämä vaikuttaa tapahtuman lopputulokseen.
Päätimme siihen, että Alice ei voinut allekirjoittaa Transfer-tapahtumaa, koska tämä mahdollisuus estettiin @verifierissä tämän tyyppiselle tapahtumalle.

Harjoitellaan jousilla ja ratkaistaan ​​sitten tämä.

RIDE Strings

Kauppa on taas mahdollista, osaamme työskennellä merkkijonojen kanssa.
Opi kirjoittamaan Waves-älysopimuksia RIDE- ja RIDE4DAPPS-palveluissa. Osa 2 (DAO – Hajautettu autonominen organisaatio)


Kaiken kaikkiaan meillä on kaikki mitä tarvitset monimutkaisen logiikan kirjoittamiseen DAO dApp.

Datatapahtumat

Datatapahtumat:
"Avaimen enimmäiskoko on 100 merkkiä, ja avain voi sisältää mielivaltaisia ​​Unicode-koodipisteitä, mukaan lukien välilyönnit ja muut ei-tulostettavat symbolit. Merkkijonoarvojen enimmäispituus on 32,768 100 tavua ja mahdollisten merkintöjen enimmäismäärä datatapahtumassa on 140. Kaiken kaikkiaan datatapahtuman enimmäiskoko on noin XNUMX kt – viitteeksi, melkein täsmälleen Shakespearen näytelmän Romeo ja Julia pituus. '."

Luomme DAO:n seuraavilla ehdoilla:
Jotta startup saa rahoitusta soittamalla getFunds() vähintään 2 osallistujan tuki - vaaditaan DAO-sijoittajia. Peruuttaa se on mahdollista täsmälleen yhtä paljon kuin merkitty summa äänestäminen DAO:n omistajat.

Tehdään 3 tyyppisiä avaimia ja lisätään logiikkaa saldojen kanssa työskentelemiseen kahdessa uudessa äänestys- ja getFunds-funktiossa:
xx…xx_ia = sijoittajat, käytettävissä oleva saldo (äänestys, talletus, kotiuttaminen)
xx…xx_sv = startupit, äänimäärä (äänestä, hanki varoja)
xx…xx_sf = startupit, äänimäärä (äänestä, hanki varoja)
xx…xx = julkinen osoite (35 merkkiä)

Huomio äänestyksessä, että meidän piti päivittää useita kenttiä kerralla:

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

WriteSet antaa meille mahdollisuuden tehdä useita tietueita kerralla yhdessä invokeScript liiketoimia.

Tältä se näyttää DAO dAppin avainarvovarastossa sen jälkeen kun Bob ja Cooper on täydennetty ia- talletukset:
Opi kirjoittamaan Waves-älysopimuksia RIDE- ja RIDE4DAPPS-palveluissa. Osa 2 (DAO – Hajautettu autonominen organisaatio)

Talletustoimintomme on muuttunut hieman:
Opi kirjoittamaan Waves-älysopimuksia RIDE- ja RIDE4DAPPS-palveluissa. Osa 2 (DAO – Hajautettu autonominen organisaatio)

Nyt tulee tärkein hetki DAO:n toiminnassa - äänestys rahoitettaville hankkeille.

Bob äänestää Neli-projektia 500000 XNUMX aallolla:

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

Opi kirjoittamaan Waves-älysopimuksia RIDE- ja RIDE4DAPPS-palveluissa. Osa 2 (DAO – Hajautettu autonominen organisaatio)

Tietosäilössä näemme kaikki tarvittavat merkinnät Neli-osoitteelle:
Opi kirjoittamaan Waves-älysopimuksia RIDE- ja RIDE4DAPPS-palveluissa. Osa 2 (DAO – Hajautettu autonominen organisaatio)
Cooper äänesti myös Neli-projektin puolesta.
Opi kirjoittamaan Waves-älysopimuksia RIDE- ja RIDE4DAPPS-palveluissa. Osa 2 (DAO – Hajautettu autonominen organisaatio)

Katsotaanpa toimintokoodia hanki varoja. Nelin on kerättävä vähintään 2 ääntä voidakseen nostaa varoja DAO:sta.
Opi kirjoittamaan Waves-älysopimuksia RIDE- ja RIDE4DAPPS-palveluissa. Osa 2 (DAO – Hajautettu autonominen organisaatio)

Neli aikoo nostaa puolet hänelle uskotusta summasta:

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

Opi kirjoittamaan Waves-älysopimuksia RIDE- ja RIDE4DAPPS-palveluissa. Osa 2 (DAO – Hajautettu autonominen organisaatio)

Hän onnistuu, eli DAO toimii!

Tarkastelimme DAO:n luomisprosessia kielellä RIDE4DAPPS.
Seuraavissa osissa tarkastellaan lähemmin koodin uudelleenmuodostusta ja tapausten testausta.

Täysi koodi sisää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
    }
}

Ensimmäinen osa
Koodi githubissa
Waves RIDE IDE
Ilmoitus apurahaohjelmasta

Lähde: will.com

Lisää kommentti