Sinau carane nulis kontrak cerdas Waves ing RIDE lan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonom Terdesentralisasi)

Sinau carane nulis kontrak cerdas Waves ing RIDE lan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonom Terdesentralisasi)

Всем Привет!

В sing pertama part, kita wis sinaoni rinci carane nggawe lan bisa karo dApp (aplikasi desentralisasi) ing Ombak RIDE IDE.

Ayo saiki nyoba sing disassembled sethitik conto.

Tahap 3. Nguji akun dApp

Sinau carane nulis kontrak cerdas Waves ing RIDE lan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonom Terdesentralisasi)

Apa masalah langsung rush kanggo voices karo Alice dapp Akun?
Pisanan:
Boob lan Cooper bisa uga ora sengaja ngirim dana menyang alamat dApp nggunakake normal transfer transaksi lan kanthi mangkono ora bakal bisa ngakses maneh.

Sarehne:
Kita ora kanthi cara apa wae mbatesi Alice kanggo mbatalake dana tanpa idin saka Boob lan/utawa Cooper. Wiwit, mbayar manungsa waé kanggo verifikasi, kabeh transaksi saka Alice bakal kaleksanan.

Ayo ndandani 2 kanthi nglarang Alice transfer transaksi. Pasang skrip sing wis didandani:
Sinau carane nulis kontrak cerdas Waves ing RIDE lan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonom Terdesentralisasi)

Kita nyoba mbatalake dhuwit recehan karo dApp Alice lan teken dheweke. Kita entuk kesalahan:
Sinau carane nulis kontrak cerdas Waves ing RIDE lan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonom Terdesentralisasi)

Nyoba mundur liwat mundur:

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

Skrip kasebut bisa digunakake lan kita nemokake titik kaping 2!

Tahap 4. Nggawe DAO kanthi voting

Sayange, basa RIDE durung nyedhiyakake kemampuan kanggo nggarap koleksi (kamus, kamus, iterator, reducer, lsp.). Nanging, kanggo operasi apa wae ing koleksi flat nilai-kunci kita bisa ngrancang sistem kanggo nggarap strings, mungguh karo tombol lan decryption sing.

Strings gampang banget kanggo concatenate, strings bisa dipisahake dening indeks.
Ayo ngumpulake lan ngurai senar kasebut minangka kasus tes lan priksa kepiye carane bisa mengaruhi asil transaksi kasebut.
Kita mutusake manawa Alice ora bisa mlebu transaksi Transfer, amarga kemungkinan iki diblokir ing @verifier kanggo jinis transaksi iki.

Ayo latihan nganggo strings banjur mutusake masalah iki.

RIDE Strings

Transaksi bisa maneh, kita ngerti carane bisa karo strings.
Sinau carane nulis kontrak cerdas Waves ing RIDE lan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonom Terdesentralisasi)


Secara total, kita duwe kabeh sing dibutuhake kanggo nulis logika kompleks DAO dApp.

Transaksi Data

Transaksi Data:
"Ukuran maksimal kanggo kunci yaiku 100 karakter, lan kunci bisa ngemot titik kode Unicode sing sewenang-wenang kalebu spasi lan simbol liyane sing ora bisa dicithak. Nilai string duwe watesan 32,768 bita lan jumlah maksimal entri sing bisa ditindakake ing transaksi data yaiku 100. Sakabèhé, ukuran maksimum transaksi data watara 140kb — kanggo referensi, meh persis dawa saka drama Shakespeare 'Romeo and Juliet. '."

Kita nggawe DAO kanthi syarat ing ngisor iki:
Supaya wiwitan entuk pendanaan kanthi nelpon getFunds() dhukungan saka paling ora 2 peserta - investor DAO dibutuhake. Mundur bakal bisa persis kaya jumlah sing dituduhake ing voting pemilik DAO.

Ayo nggawe 3 jinis kunci lan nambah logika kanggo nggarap saldo ing 2 fungsi anyar voting lan getFunds:
xx…xx_iku = investor, imbangan kasedhiya (vote, deposit, penarikan)
xx…xx_sv = wiwitan, jumlah swara (vote, getFunds)
xx…xx_sf = wiwitan, jumlah swara (vote, getFunds)
xx…xx = alamat umum (35 karakter)

Kabar ing Vote kita kudu nganyari sawetara lapangan bebarengan:

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

WriteSet ngidini kita nggawe sawetara rekaman bebarengan ing siji invokeScript transaksi.

Iki katon kaya ing toko kunci-nilai saka DAO dApp sawise Bob lan Cooper diisi maneh ia- simpenan:
Sinau carane nulis kontrak cerdas Waves ing RIDE lan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonom Terdesentralisasi)

Fungsi simpenan kita wis rada owah:
Sinau carane nulis kontrak cerdas Waves ing RIDE lan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonom Terdesentralisasi)

Saiki dadi momen sing paling penting ing kegiatan DAO - milih kanggo proyek kanggo pendanaan.

Bob milih proyek Neli ing 500000 wavelet:

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

Sinau carane nulis kontrak cerdas Waves ing RIDE lan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonom Terdesentralisasi)

Ing nyimpen data, kita ndeleng kabeh entri sing dibutuhake kanggo alamat Neli:
Sinau carane nulis kontrak cerdas Waves ing RIDE lan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonom Terdesentralisasi)
Cooper uga milih kanggo proyek Neli.
Sinau carane nulis kontrak cerdas Waves ing RIDE lan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonom Terdesentralisasi)

Ayo kang njupuk dipikir ing kode fungsi getFunds. Neli kudu ngumpulake paling ora 2 suara supaya bisa narik dana saka DAO.
Sinau carane nulis kontrak cerdas Waves ing RIDE lan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonom Terdesentralisasi)

Neli arep mbatalake setengah saka jumlah sing dipasrahake marang dheweke:

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

Sinau carane nulis kontrak cerdas Waves ing RIDE lan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonom Terdesentralisasi)

Dheweke sukses, yaiku, kerja DAO!

Kita mriksa proses nggawe DAO ing basa kasebut RIDE4DAPPS.
Ing bagean ing ngisor iki, kita bakal nliti babagan refactoring kode lan tes kasus.

Kode lengkap ing 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
    }
}

Bagéan pisanan
Kode ing github
Ombak RIDE IDE
Pengumuman Program Hibah

Source: www.habr.com

Add a comment