Mempelajari cara menulis kontrak pintar Waves di RIDE dan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonomi Terdesentralisasi)

Mempelajari cara menulis kontrak pintar Waves di RIDE dan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonomi Terdesentralisasi)

Hello!

Π’ pertama bagian, kami telah memeriksa secara rinci cara membuat dan bekerja dengan dApp (aplikasi terdesentralisasi) di Gelombang RIDE IDE.

Sekarang mari kita uji sedikit yang dibongkar contoh.

Tahap 3. Menguji akun dApp

Mempelajari cara menulis kontrak pintar Waves di RIDE dan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonomi Terdesentralisasi)

Masalah apa yang segera mengalir ke suara-suara dengan Alice dApp Rekening?
Pertama:
Boob dan Cooper mungkin secara tidak sengaja mengirim dana ke alamat dApp menggunakan yang biasa transfer transaksi dan dengan demikian tidak akan dapat mengaksesnya kembali.

Kedua:
Kami sama sekali tidak membatasi Alice untuk menarik dana tanpa persetujuan dari Boob dan/atau Cooper. Karena, perhatikan verifikasi, semua transaksi dari Alice akan dieksekusi.

Mari perbaiki 2 dengan melarang Alice transfer transaksi. Terapkan skrip yang diperbaiki:
Mempelajari cara menulis kontrak pintar Waves di RIDE dan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonomi Terdesentralisasi)
οΏΌ
Kami mencoba menarik koin dengan dApp Alice dan tanda tangannya. Kami mendapatkan kesalahan:
Mempelajari cara menulis kontrak pintar Waves di RIDE dan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonomi Terdesentralisasi)

Mencoba menarik melalui penarikan:

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

Skripnya berfungsi dan kami menemukan poin ke-2!

Tahap 4. Buat DAO dengan pemungutan suara

Sayangnya, bahasa RIDE belum menyediakan kemampuan untuk bekerja dengan koleksi (kamus, kamus, iterator, reduksi, dll.). Namun, untuk setiap operasi pada koleksi datar nilai kunci kita dapat merancang sistem untuk bekerja dengan string, masing-masing dengan kunci dan dekripsinya.

String sangat mudah digabungkan, string dapat dipisahkan dengan indeks.
Mari kumpulkan dan parsing string sebagai kasus uji dan periksa bagaimana hal ini akan memengaruhi hasil transaksi.
Kami menetapkan fakta bahwa Alice tidak dapat menandatangani transaksi Transfer, karena kemungkinan ini diblokir di @verifier untuk jenis transaksi ini.

Mari berlatih dengan string lalu selesaikan ini.

RIDE String

Transaksi dimungkinkan lagi, kami tahu cara bekerja dengan string.
Mempelajari cara menulis kontrak pintar Waves di RIDE dan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonomi Terdesentralisasi)

οΏΌ
Secara total, kami memiliki semua yang Anda butuhkan untuk menulis logika kompleks DAO dApp.

Transaksi Data

Transaksi Data:
β€œUkuran maksimum untuk sebuah kunci adalah 100 karakter, dan sebuah kunci dapat berisi poin kode Unicode arbitrer termasuk spasi dan simbol lain yang tidak dapat dicetak. Nilai string memiliki batas 32,768 byte dan jumlah maksimum entri yang mungkin dalam transaksi data adalah 100. Secara keseluruhan, ukuran maksimum transaksi data adalah sekitar 140kb β€” untuk referensi, hampir sama dengan panjang drama Shakespeare 'Romeo and Juliet '. ”

Kami membuat DAO dengan ketentuan sebagai berikut:
Agar startup mendapatkan pendanaan dengan menelepon dapatkan Dana() dukungan minimal 2 peserta - investor DAO diperlukan. menarik itu akan mungkin persis sebanyak jumlah yang ditunjukkan pemungutan suara pemilik DAO.

Mari buat 3 jenis kunci dan tambahkan logika untuk bekerja dengan saldo dalam 2 fungsi baru, pilih dan dapatkan Dana:
xx…xx_ia = investor, saldo tersedia (suara, deposit, penarikan)
xx…xx_sv = startup, jumlah suara (pilih, dapatkan Dana)
xx…xx_sf = startup, jumlah suara (pilih, dapatkan Dana)
xx…xx = alamat publik (35 karakter)

Perhatikan di Vote kami perlu memperbarui beberapa bidang sekaligus:

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

WriteSet memungkinkan kita membuat beberapa record sekaligus dalam satu invokeScript transaksi.

Beginilah tampilannya di penyimpanan nilai kunci DAO dApp setelah Bob dan Cooper diisi ulang ia- deposito:
Mempelajari cara menulis kontrak pintar Waves di RIDE dan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonomi Terdesentralisasi)

Fungsi setoran kami sedikit berubah:
Mempelajari cara menulis kontrak pintar Waves di RIDE dan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonomi Terdesentralisasi)

Sekarang tibalah momen terpenting dalam aktivitas DAO - Pilih untuk proyek-proyek untuk pendanaan.

Bob memilih proyek Neli pada 500000 wavelet:

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

Mempelajari cara menulis kontrak pintar Waves di RIDE dan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonomi Terdesentralisasi)

Di penyimpanan data, kami melihat semua entri yang diperlukan untuk alamat Neli:
Mempelajari cara menulis kontrak pintar Waves di RIDE dan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonomi Terdesentralisasi)
Cooper juga memilih proyek Neli.
Mempelajari cara menulis kontrak pintar Waves di RIDE dan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonomi Terdesentralisasi)

Mari kita lihat kode fungsinya dapatkan Dana. Neli harus mengumpulkan minimal 2 suara untuk dapat mencairkan dana dari DAO.
Mempelajari cara menulis kontrak pintar Waves di RIDE dan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonomi Terdesentralisasi)

Neli akan menarik setengah dari jumlah yang dipercayakan kepadanya:

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

Mempelajari cara menulis kontrak pintar Waves di RIDE dan RIDE4DAPPS. Bagian 2 (DAO - Organisasi Otonomi Terdesentralisasi)

Dia berhasil, yaitu, DAO berfungsi!

Kami meninjau proses pembuatan DAO dalam bahasa tersebut RIDE4DAPPS.
Pada bagian berikut, kita akan melihat lebih dekat pemfaktoran ulang kode dan pengujian kasus.

Kode lengkap di Gelombang 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
    }
}

Bagian pertama
Kode di github
Gelombang RIDE IDE
Pengumuman program hibah

Sumber: www.habr.com

Tambah komentar