Pag-aaral na magsulat ng mga Waves smart contract sa RIDE at RIDE4DAPPS. Bahagi 2 (DAO - Desentralisadong Autonomous Organization)

Pag-aaral na magsulat ng mga Waves smart contract sa RIDE at RIDE4DAPPS. Bahagi 2 (DAO - Desentralisadong Autonomous Organization)

Kumusta sa lahat!

В una bahaging tiningnan namin nang detalyado kung paano lumikha at magtrabaho kasama ang dApp (desentralisadong aplikasyon) sa Waves RIDE IDE.

Subukan natin ng kaunti ang na-disassemble ngayon halimbawa.

Stage 3. Pagsubok sa dApp account

Pag-aaral na magsulat ng mga Waves smart contract sa RIDE at RIDE4DAPPS. Bahagi 2 (DAO - Desentralisadong Autonomous Organization)

Anong mga problema ang agad na lumabas sa iyo kasama si Alice? dApp Account?
Una:
Maaaring hindi sinasadyang magpadala sina Boob at Cooper ng mga pondo sa dApp address gamit ang regular ilipat mga transaksyon at sa gayon ay hindi maa-access ang mga ito pabalik.

Pangalawa:
Hindi namin pinaghihigpitan si Alice sa anumang paraan sa pag-withdraw ng mga pondo nang walang pag-apruba ni Boob at/o Cooper. Dahil, bigyang pansin ang pag-verify, lahat ng mga transaksyon mula kay Alice ay isasagawa.

Ayusin natin ang 2nd sa pamamagitan ng pagbabawal kay Alice ilipat mga transaksyon. I-deploy natin ang naitama na script:
Pag-aaral na magsulat ng mga Waves smart contract sa RIDE at RIDE4DAPPS. Bahagi 2 (DAO - Desentralisadong Autonomous Organization)

Sinusubukan naming mag-withdraw ng mga barya mula sa dApp Alice at sa kanyang lagda. Nakakakuha kami ng error:
Pag-aaral na magsulat ng mga Waves smart contract sa RIDE at RIDE4DAPPS. Bahagi 2 (DAO - Desentralisadong Autonomous Organization)

Subukan nating mag-withdraw sa pamamagitan ng withdraw:

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

Gumagana ang script at nalaman namin ang 2nd point!

Stage 4. Gumawa ng DAO na may pagboto

Sa kasamaang palad, ang wikang RIDE ay hindi pa nagbibigay ng kakayahang magtrabaho kasama ang mga koleksyon (mga diksyunaryo, iterator, reducer, atbp.). Gayunpaman, para sa anumang mga operasyon na may mga flat na koleksyon mahalagang halaga maaari tayong magdisenyo ng isang sistema para sa pagtatrabaho sa mga string, nang naaayon sa mga susi at kanilang pag-decryption.

Ang mga string ay napakadaling pagsamahin; ang mga string ay maaaring paghiwalayin ng mga index.
Mangolekta at mag-parse tayo ng string bilang isang halimbawa ng pagsubok at suriin kung paano ito nakakaapekto sa kinalabasan ng transaksyon.
Napagkasunduan namin na hindi mapirmahan ni Alice ang transaksyon sa Paglipat, dahil na-block ang kakayahang ito sa @verifier para sa ganitong uri ng transaksyon.

Magsanay tayo gamit ang mga string at pagkatapos ay lutasin ito.

RIDE Strings

Posible muli ang transaksyon, alam namin kung paano magtrabaho sa mga string.
Pag-aaral na magsulat ng mga Waves smart contract sa RIDE at RIDE4DAPPS. Bahagi 2 (DAO - Desentralisadong Autonomous Organization)


Sa kabuuan, mayroon kaming lahat ng kailangan upang magsulat ng kumplikadong lohika DAO dApp.

Mga Transaksyon ng Data

Mga Transaksyon ng Data:
“Ang maximum na laki para sa isang key ay 100 character, at ang isang key ay maaaring maglaman ng mga arbitrary na Unicode code point kabilang ang mga puwang at iba pang hindi napi-print na mga simbolo. Ang mga string value ay may limitasyon na 32,768 bytes at ang maximum na bilang ng posibleng mga entry sa transaksyon ng data ay 100. Sa pangkalahatan, ang maximum na laki ng transaksyon ng data ay humigit-kumulang 140kb — para sanggunian, halos eksaktong haba ng dula ni Shakespeare na 'Romeo and Juliet '."

Lumilikha kami ng DAO na may mga sumusunod na kundisyon:
Upang ang isang startup ay makatanggap ng pondo sa pamamagitan ng pagtawag getFunds() ang suporta ng hindi bababa sa 2 kalahok - DAO investor - ay kinakailangan. Mag-withdraw ito ay magiging posible nang eksakto hangga't ang kabuuang ipinahiwatig sa pagboto Mga may-ari ng DAO.

Gumawa tayo ng 3 uri ng mga susi at magdagdag ng lohika para sa pagtatrabaho sa mga balanse sa 2 bagong function na boto at getFunds:
xx…xx_ia = mamumuhunan, magagamit na balanse (boto, deposito, withdrawal)
xx…xx_sv = mga startup, bilang ng mga boto (bumoto, getFunds)
xx…xx_sf = mga startup, bilang ng mga boto (bumoto, getFunds)
xx…xx = pampublikong address (35 character)

Pakitandaan na sa Pagboto kailangan naming i-update ang ilang field nang sabay-sabay:

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

Ang WriteSet ay nagpapahintulot sa amin na gumawa ng ilang mga tala nang sabay-sabay sa loob ng isa invokeScript mga transaksyon.

Ito ang hitsura sa key-value storage ng DAO dApp, pagkatapos mag-replenished nina Bob at Cooper ia-mga deposito:
Pag-aaral na magsulat ng mga Waves smart contract sa RIDE at RIDE4DAPPS. Bahagi 2 (DAO - Desentralisadong Autonomous Organization)

Ang aming function ng deposito ay bahagyang nagbago:
Pag-aaral na magsulat ng mga Waves smart contract sa RIDE at RIDE4DAPPS. Bahagi 2 (DAO - Desentralisadong Autonomous Organization)

Dumating na ngayon ang pinakamahalagang sandali sa mga aktibidad ng DAO - bumoto para sa mga proyektong matustusan.

Bumoto si Bob para sa 500000 wavelets project ni Neli:

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

Pag-aaral na magsulat ng mga Waves smart contract sa RIDE at RIDE4DAPPS. Bahagi 2 (DAO - Desentralisadong Autonomous Organization)

Sa data store nakikita namin ang lahat ng kinakailangang mga entry para sa address ni Neli:
Pag-aaral na magsulat ng mga Waves smart contract sa RIDE at RIDE4DAPPS. Bahagi 2 (DAO - Desentralisadong Autonomous Organization)
Bumoto din si Cooper para sa proyekto ng Neli.
Pag-aaral na magsulat ng mga Waves smart contract sa RIDE at RIDE4DAPPS. Bahagi 2 (DAO - Desentralisadong Autonomous Organization)

Tingnan natin ang function code getFunds. Dapat mangolekta si Neli ng hindi bababa sa 2 boto para makapag-withdraw ng pondo mula sa DAO.
Pag-aaral na magsulat ng mga Waves smart contract sa RIDE at RIDE4DAPPS. Bahagi 2 (DAO - Desentralisadong Autonomous Organization)

Babawiin ni Neli ang kalahati ng halagang ipinagkatiwala sa kanya:

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

Pag-aaral na magsulat ng mga Waves smart contract sa RIDE at RIDE4DAPPS. Bahagi 2 (DAO - Desentralisadong Autonomous Organization)

Nagtagumpay siya, ibig sabihin, gumagana ang DAO!

Tiningnan namin ang proseso ng paglikha ng DAO sa wika RIDE4DAPPS.
Sa mga sumusunod na bahagi, susuriin nating mabuti ang code refactoring at case testing.

Buong bersyon ng code sa 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
    }
}

Ang unang bahagi
Code sa GitHub
Waves RIDE IDE
Anunsyo ng programa ng pagbibigay

Pinagmulan: www.habr.com

Magdagdag ng komento