Waves okosszerződések írását tanuljuk RIDE és RIDE4DAPPS nyelven. 2. rész (DAO — Decentralizált Autonóm Szervezet)

Waves okosszerződések írását tanuljuk RIDE és RIDE4DAPPS nyelven. 2. rész (DAO — Decentralizált Autonóm Szervezet)

Mindenkinek szia!

A első Részletekbe menően megvizsgáltuk, hogyan kell létrehozni és dolgozni a dApp (decentralizált alkalmazás) alkalmazással Waves RIDE IDE.

Most egy kicsit teszteljük az elemzett példám.

3. lépés. dApp fiók tesztelése

Waves okosszerződések írását tanuljuk RIDE és RIDE4DAPPS nyelven. 2. rész (DAO — Decentralizált Autonóm Szervezet)

Milyen problémák merülnek fel Alice-szal kapcsolatban? dApp Fiók?
Először is:
Boob és Cooper véletlenül elküldhetik a dApp címére a forrást egy szokványos átutalás tranzakcióval, és így nem tudják visszanyerni a hozzáférést.

Másodszor:
Nem korlátozzuk Alicet a források kivezetésében Boob vagy Cooper beleegyezése nélkül. Mint látható, minden Alice-tól érkező tranzakciót végrehajtanak.

Javítsuk a második pontot azzal, hogy megtiltjuk Alicenak átutalás a tranzakciókat. Telepítjük a javított szkriptet:
Waves okosszerződések írását tanuljuk RIDE és RIDE4DAPPS nyelven. 2. rész (DAO — Decentralizált Autonóm Szervezet)

Próbálom megvonni a pénzeket a dApp Alice és az ő aláírása segítségével. Hibát kapunk:
Waves okosszerződések írását tanuljuk RIDE és RIDE4DAPPS nyelven. 2. rész (DAO — Decentralizált Autonóm Szervezet)

Próbálkozunk a withdraw segítségével:

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

A szkript működik, és a második ponttal megoldottuk!

4. lépés. DAO létrehozása szavazással

Sajnos, a RIDE nyelvben még nincsenek lehetőségek gyűjtemények (szótárak, iterátorok, redukálók stb.) kezelésére. Azonban bármilyen művelethez lapos gyűjteményekkel kulcs-érték tervezhetünk egy rendszer a sztringek kezelésére, így a kulcsok és azok dekódolása.

A sztringeket nagyon egyszerű összefűzni, a sztringeket indexek alapján lehet szétválasztani.
Létrehozunk egy tesztpéldát, amelyben összegyűjtjük és elemezzük a sztringet, és ellenőrizzük, hogyan befolyásolja a tranzakció kimenetelét.
Ott tartottunk, hogy Alice nem tudta aláírni a Transfer tranzakciót, mivel ez a lehetőség le volt tiltva az @verifier számára az ilyen típusú tranzakciók esetében.

Gyakorlatozunk a sztringekkel, majd engedjük ezt.

RIDE Strings

A tranzakció újra lehetséges, tudunk dolgozni a sztringekkel.
Waves okosszerződések írását tanuljuk RIDE és RIDE4DAPPS nyelven. 2. rész (DAO — Decentralizált Autonóm Szervezet)


Összességében minden szükségesünk megvan a bonyolult logika írásához DAO dApp.

Adat tranzakciók

Adat tranzakciók:
„A kulcs maximális hossza 100 karakter, és a kulcs tetszőleges Unicode kódpontokat, beleértve a szóközöket és egyéb nem nyomtatható szimbólumokat tartalmazhat. A sztring értékek hossza maximum 32,768 bájt, és a max. lehetséges bejegyzések száma adat tranzakciónként 100. Összességében az adat tranzakció maximális mérete körülbelül 140kb — referenciaként majdnem pontosan akkora, mint Shakespeare 'Romeo és Júlia' című drámája.”

DAO-t hozunk létre a következő feltételekkel:
Ahhoz, hogy a startup finanszírozást kapjon, ki kell váltania a getFunds() minimálisan 2 DAO befektető támogatása szükséges. [user@testhost ~]$ tail -1 temp Lalalala... annyit lehet majd kérni, amennyit összesen a szavazáson a DAO tulajdonosai jeleztek.

Hozzunk létre 3 típust, és adjunk logikát a egyenlegekkel való munkához a vote és getFunds két új funkcióban:
xx…xx_ia = befektetők, elérhető egyensúly (szavazás, betét, kivét)
xx…xx_sv = startupok, szavazatok száma (szavazás, getFunds)
xx…xx_sf = startupok, szavazatok száma (szavazás, getFunds)
xx…xx = nyilvános cím (35 karakter)

Ne feledje, a Vote során több mezőt is frissítenünk kellett:

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

A WriteSet lehetővé teszi, hogy egyszerre több bejegyzést készítsünk egy invokeScript transaction.

Így néz ki a DAO dApp kulcs-érték tárolójában, miután Bob és Cooper feltöltötték ia-betétek:
Waves okosszerződések írását tanuljuk RIDE és RIDE4DAPPS nyelven. 2. rész (DAO — Decentralizált Autonóm Szervezet)

A betét funkciónk kissé megváltozott:
Waves okosszerződések írását tanuljuk RIDE és RIDE4DAPPS nyelven. 2. rész (DAO — Decentralizált Autonóm Szervezet)

Most jön a legfontosabb pillanat a DAO működésében — szavazás a finanszírozásra szánt projektekre.

Bob 500000 wavelets-tel szavaz a Neli projektre:

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

Waves okosszerződések írását tanuljuk RIDE és RIDE4DAPPS nyelven. 2. rész (DAO — Decentralizált Autonóm Szervezet)

Az adatbázisban látjuk az összes szükséges bejegyzést Neli címéhez:
Waves okosszerződések írását tanuljuk RIDE és RIDE4DAPPS nyelven. 2. rész (DAO — Decentralizált Autonóm Szervezet)
Cooper is szavazott a Neli projektre.
Waves okosszerződések írását tanuljuk RIDE és RIDE4DAPPS nyelven. 2. rész (DAO — Decentralizált Autonóm Szervezet)

Nézzük meg a function getFunds. Nelinek minimum 2 szavazatra van szüksége ahhoz, hogy pénzt tudjon felvenni a DAO-ból.
Waves okosszerződések írását tanuljuk RIDE és RIDE4DAPPS nyelven. 2. rész (DAO — Decentralizált Autonóm Szervezet)

Neli a rá bízott összeg felét szeretné felvenni:

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

Waves okosszerződések írását tanuljuk RIDE és RIDE4DAPPS nyelven. 2. rész (DAO — Decentralizált Autonóm Szervezet)

Ez sikerül neki, tehát a DAO működik!

Megvizsgáltuk a DAO létrehozásának folyamatát a RIDE4DAPPS.
nyelven. A következő részekben részletesebben foglalkozunk a kód refaktorálásával és a tesztelési esetekkel.

A kód teljes verziója itt található: 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
    }
}

Első rész
Kód a GitHubon
Waves RIDE IDE
A pályázati program bejelentése

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster