Tanulj meg Waves intelligens szerződéseket írni RIDE és RIDE4DAPPS rendszeren. 2. rész (DAO – Decentralizált autonóm szervezet)

Tanulj meg Waves intelligens szerződéseket írni RIDE és RIDE4DAPPS rendszeren. 2. rész (DAO – Decentralizált autonóm szervezet)

Hello!

В az első részben részletesen megvizsgáltuk, hogyan lehet dApp-ot (decentralizált alkalmazás) létrehozni és dolgozni Waves RIDE IDE.

Teszteljük most egy kicsit a szétszedettet példa.

3. szakasz: A dApp fiók tesztelése

Tanulj meg Waves intelligens szerződéseket írni RIDE és RIDE4DAPPS rendszeren. 2. rész (DAO – Decentralizált autonóm szervezet)

Milyen problémák merülnek fel azonnal Alice-szel? DAPP -Fiók?
Először:
Boob és Cooper véletlenül pénzt küldhet a dApp címére a hagyományos használatával átruházás tranzakciókat, és így nem férhet hozzájuk vissza.

Másodszor:
Semmilyen módon nem korlátozzuk Alice-t abban, hogy Boob és/vagy Cooper jóváhagyása nélkül vegyen fel pénzt. Mivel ügyeljen az ellenőrzésre, Alice minden tranzakciója végrehajtásra kerül.

Javítsuk ki a másodikat Alice kitiltásával átruházás tranzakciók. Telepítsük a javított szkriptet:
Tanulj meg Waves intelligens szerződéseket írni RIDE és RIDE4DAPPS rendszeren. 2. rész (DAO – Decentralizált autonóm szervezet)

Megpróbáljuk visszavonni az érméket a dApp Alice-től és az aláírásától. Hibát kapunk:
Tanulj meg Waves intelligens szerződéseket írni RIDE és RIDE4DAPPS rendszeren. 2. rész (DAO – Decentralizált autonóm szervezet)

Próbáljuk meg a visszavonással visszavonni:

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

A forgatókönyv működik, és kitaláltuk a 2. pontot!

4. szakasz. Hozzon létre egy DAO-t szavazással

Sajnos a RIDE nyelv még nem ad lehetőséget gyűjteményekkel (szótári szótárak, iterátorok, reduktorok stb.) való munkavégzésre. Azonban minden lapos gyűjteménnyel végzett művelethez kulcs érték megtervezhetünk egy rendszert a stringekkel való munkavégzéshez, ennek megfelelően a kulcsokkal és azok visszafejtésével.

A karakterláncokat nagyon könnyű összefűzni, a karakterláncokat indexekkel lehet elválasztani.
Gyűjtsünk össze és elemezzünk egy karakterláncot tesztpéldaként, és ellenőrizzük, hogy ez hogyan befolyásolja a tranzakció kimenetelét.
Megállapodtunk abban, hogy Alice nem tudta aláírni az Átigazolási tranzakciót, mivel ez a lehetőség a @verifier-ben le van tiltva az ilyen típusú tranzakcióknál.

Gyakoroljunk a húrokkal, majd oldjuk meg ezt.

RIDE Húrok

A tranzakció újra lehetséges, tudjuk, hogyan kell a karakterláncokkal dolgozni.
Tanulj meg Waves intelligens szerződéseket írni RIDE és RIDE4DAPPS rendszeren. 2. rész (DAO – Decentralizált autonóm szervezet)


Összességében mindenünk megvan, ami az összetett logika megírásához szükséges DAO dApp.

Adattranzakciók

Adattranzakciók:
"Egy kulcs maximális mérete 100 karakter, és egy kulcs tetszőleges Unicode kódpontokat tartalmazhat, beleértve a szóközöket és más nem nyomtatható szimbólumokat. A karakterláncértékek korlátja 32,768 100 bájt, és a lehetséges bejegyzések maximális száma az adattranzakcióban 140. Összességében az adattranzakció maximális mérete körülbelül XNUMX kb – referenciaként majdnem pontosan annyi, mint Shakespeare Rómeó és Júlia című drámájának hossza. '.”

DAO-t hozunk létre a következő feltételekkel:
Ahhoz, hogy egy startup támogatást kaphasson telefonon getFunds() legalább 2 résztvevő - DAO befektető - támogatása szükséges. Visszavonás pontosan annyi lesz lehetséges, amennyi a feltüntetett összesen szavazás DAO tulajdonosok.

Készítsünk 3 típusú kulcsot, és adjunk hozzá logikát az egyenlegekkel való munkavégzéshez 2 új szavazat és getFunds függvényben:
xx…xx_ia = befektetők, rendelkezésre álló egyenleg (szavazás, befizetés, visszavonás)
xx…xx_sv = startupok, szavazatok száma (szavazás, pénzszerzés)
xx…xx_sf = startupok, szavazatok száma (szavazás, pénzszerzés)
xx…xx = nyilvános cím (35 karakter)

Felhívjuk figyelmét, hogy a Szavazásban egyszerre több mezőt kellett frissítenünk:

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

A WriteSet lehetővé teszi, hogy több rekordot készítsünk egyszerre egyen belül invokeScript tranzakciók.

Í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:
Tanulj meg Waves intelligens szerződéseket írni RIDE és RIDE4DAPPS rendszeren. 2. rész (DAO – Decentralizált autonóm szervezet)

Befizetési funkciónk némileg megváltozott:
Tanulj meg Waves intelligens szerződéseket írni RIDE és RIDE4DAPPS rendszeren. 2. rész (DAO – Decentralizált autonóm szervezet)

Most jön a legfontosabb pillanat a DAO tevékenységében - szavazás finanszírozandó projektekhez.

Bob Neli 500000 XNUMX wavelet projektjére szavaz:

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

Tanulj meg Waves intelligens szerződéseket írni RIDE és RIDE4DAPPS rendszeren. 2. rész (DAO – Decentralizált autonóm szervezet)

Az adattárban minden szükséges bejegyzést látunk Neli címéhez:
Tanulj meg Waves intelligens szerződéseket írni RIDE és RIDE4DAPPS rendszeren. 2. rész (DAO – Decentralizált autonóm szervezet)
Cooper is a Neli projektre szavazott.
Tanulj meg Waves intelligens szerződéseket írni RIDE és RIDE4DAPPS rendszeren. 2. rész (DAO – Decentralizált autonóm szervezet)

Nézzük meg a függvénykódot getFunds. Nelinek legalább 2 szavazatot kell összegyűjtenie, hogy pénzt vonhasson ki a DAO-tól.
Tanulj meg Waves intelligens szerződéseket írni RIDE és RIDE4DAPPS rendszeren. 2. rész (DAO – Decentralizált autonóm szervezet)

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

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

Tanulj meg Waves intelligens szerződéseket írni RIDE és RIDE4DAPPS rendszeren. 2. rész (DAO – Decentralizált autonóm szervezet)

Neki sikerül, vagyis működik a DAO!

Megnéztük a DAO létrehozásának folyamatát a nyelven RIDE4DAPPS.
A következő részekben közelebbről megvizsgáljuk a kódrefaktorálást és az esettesztet.

A kód teljes verziója itt 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 támogatási program meghirdetése

Forrás: will.com

Hozzászólás