Učimo se pisati Waves pametne pogodbe na RIDE in RIDE4DAPPS. Del 2 (DAO — Decentralizirana avtonomna organizacija)

Učimo se pisati Waves pametne pogodbe na RIDE in RIDE4DAPPS. Del 2 (DAO — Decentralizirana avtonomna organizacija)

Zdravo svima!

V prvi dio detaljno smo razmotrili kako kreirati i raditi s dApp (decentraliziranom aplikacijom) u Waves RIDE IDE.

Sada ćemo malo testirati razrađeni primer.

Faza 3. Testiranje dApp računa

Učimo se pisati Waves pametne pogodbe na RIDE in RIDE4DAPPS. Del 2 (DAO — Decentralizirana avtonomna organizacija)

Koje se probleme odmah uočava kod Alice dApp Račun?
Prvo:
Boob i Cooper mogu slučajno poslati sredstva na adresu dApp putem obične prenos transakcije i tako neće moći ponovno pristupiti njima.

Drugo:
Mi nikako ne ograničavamo Alice u isplati sredstava bez odobrenja od Boob ili(ili) Coopera. Kao što, obratite pažnju na verifikaciju, sve transakcije od Alice će se izvršavati.

Ispravimo drugu, zabranjujući Alice prenos transakcije. Deploy-amo ispravljeni skript:
Učimo se pisati Waves pametne pogodbe na RIDE in RIDE4DAPPS. Del 2 (DAO — Decentralizirana avtonomna organizacija)

Pokušavamo povući novčiće s dApp Alice i njenim potpisom. Dobivamo grešku:
Učimo se pisati Waves pametne pogodbe na RIDE in RIDE4DAPPS. Del 2 (DAO — Decentralizirana avtonomna organizacija)

Pokušavamo povući putem withdraw:

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

Skript radi i s drugim točkom smo se razjasnili!

Faza 4. Kreiramo DAO s glasovanjem

Nažalost, u jeziku RIDE trenutno nije predviđena mogućnost rada s kolekcijama (riječnici-riječnika, iteratori, reduktori itd.). Međutim, za bilo koje operacije s ravnim kolekcijama key-value možemo projektirati sustav rada sa stringovima, prema tome s ključevima i njihovim dekodiranjem.

Stringove je vrlo lako spojiti, stringove možemo dijeliti prema indeksima.
Pokažimo primjer kako ćemo sastaviti i razložiti string i provjeriti kako to utječe na ishod transakcije.
Stali smo na tome da Alice nije mogla potpisati Transfer transakciju, jer je ta mogućnost bila blokirana u @verifier za tu vrstu transakcija.

Pokažimo se sa stringovima i zatim ćemo to odobriti.

RIDE Stringovi

Transakcija je ponovno moguća, možemo raditi sa stringovima.
Učimo se pisati Waves pametne pogodbe na RIDE in RIDE4DAPPS. Del 2 (DAO — Decentralizirana avtonomna organizacija)


Dakle, imamo sve što nam je potrebno za pisanje složene logike DAO dApp.

Podatkovne transakcije

Podatkovne transakcije:
“Maksimalna veličina za ključ je 100 znakova, a ključ može sadržavati proizvoljne Unicode kodne točke uključujući razmake i druge nevidljive simbole. String vrijednosti imaju limit od 32,768 bajta, a maksimalni broj mogućih unosa u podatkovnoj transakciji je 100. Ukupna maksimalna veličina podatkovne transakcije iznosi oko 140kb — za referencu, gotovo točno dužina Šekspirove drame ‘Romeo i Julija’.”

Kreiramo DAO s sljedećim uvjetima:
Da bi startup dobio financijska sredstva, pozivajući getFunds() potrebna je podrška najmanje 2 sudionika — investitora DAO. Povući može se povući točno onoliko koliko je ukupno navedeno na glasovanju власници DAO.

Хајде да направимо 3 типа кључева и додамо логичке операције за управљање балансима у две нове функције vote и getFunds:
xx…xx_ia = инвеститори, доступан баланс (vote, deposit, withdrawal)
xx…xx_sv = стартупи, број гласова (vote, getFunds)
xx…xx_sf = стартупи, број гласова (vote, getFunds)
xx…xx = јавна адреса (35 знакова)

Обратите пажњу да у Vote морамо обновити неколико поља:

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

WriteSet нам омогућава да направимо више записа у оквиру једне invokeScript транзакције.

Овако изгледа у key-value складишту DAO dApp, након што су Bob и Cooper допунили ia-депозити:
Učimo se pisati Waves pametne pogodbe na RIDE in RIDE4DAPPS. Del 2 (DAO — Decentralizirana avtonomna organizacija)

Функција депозита је благом променила:
Učimo se pisati Waves pametne pogodbe na RIDE in RIDE4DAPPS. Del 2 (DAO — Decentralizirana avtonomna organizacija)

Сада долази најважнији тренутак у деловању DAO — гласање за пројекте које треба финансирати.

Bob гласа за пројекат Neli са 500000 wavelets:

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

Učimo se pisati Waves pametne pogodbe na RIDE in RIDE4DAPPS. Del 2 (DAO — Decentralizirana avtonomna organizacija)

У складишту података видимо све потребне записа за адресу Neli:
Učimo se pisati Waves pametne pogodbe na RIDE in RIDE4DAPPS. Del 2 (DAO — Decentralizirana avtonomna organizacija)
Купер је такође гласао за пројекат Neli.
Učimo se pisati Waves pametne pogodbe na RIDE in RIDE4DAPPS. Del 2 (DAO — Decentralizirana avtonomna organizacija)

Погледајмо код функције getFunds. Neli мора сакупити најмање 2 гласа да би могла повући средства из DAO.
Učimo se pisati Waves pametne pogodbe na RIDE in RIDE4DAPPS. Del 2 (DAO — Decentralizirana avtonomna organizacija)

Neli планира да повуче половину износа који јој је поверен:

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

Učimo se pisati Waves pametne pogodbe na RIDE in RIDE4DAPPS. Del 2 (DAO — Decentralizirana avtonomna organizacija)

Успева, што значи да DAO функционише!

Размотрили смо процес стварања DAO на језику RIDE4DAPPS.
У следећим деловима ћемо детаљније размотрити рефакторинг кода и тестирање случајева.

Пуна верзија кода у 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
    }
}

Prvi del
Код на гитхабу
Waves RIDE IDE
Анонс програма грантова

Izvor: habr.com

Kupite zanesljivo gostovanje za spletne strani z zaščito pred DDoS, VPS VDS strežniki 🔥 Kupite zanesljivo gostovanje za spletne strani z zaščito pred DDoS, VPS VDS strežniki | ProHoster