Lerni skribi Waves inteligentajn kontraktojn sur RIDE kaj RIDE4DAPPS. Parto 2 (DAO - Malcentra Aŭtonoma Organizo)

Lerni skribi Waves inteligentajn kontraktojn sur RIDE kaj RIDE4DAPPS. Parto 2 (DAO - Malcentra Aŭtonoma Organizo)

Saluton ĉiuj!

В la unua parto ni detale rigardis kiel krei kaj labori kun dApp (malcentralizita aplikaĵo). Waves RIDE IDE.

Ni provu nun la malmuntitan ekzemplo.

Etapo 3. Provante la konton dApp

Lerni skribi Waves inteligentajn kontraktojn sur RIDE kaj RIDE4DAPPS. Parto 2 (DAO - Malcentra Aŭtonoma Organizo)

Kiuj problemoj tuj saltas al vi kun Alico? dApp Konto?
Unue:
Boob kaj Cooper eble hazarde sendas financon al la dApp-adreso uzante regulan transigo transakcioj kaj tiel ne povos aliri ilin reen.

Due:
Ni neniel limigas Alicion retiri financon sen la aprobo de Boob kaj/aŭ Cooper. Ĉar, atentu kontroli, ĉiuj transakcioj de Alice estos efektivigitaj.

Ni riparu 2-a per malpermeso de Alicio transigo transakcioj. Ni disfaldu la korektitan skripton:
Lerni skribi Waves inteligentajn kontraktojn sur RIDE kaj RIDE4DAPPS. Parto 2 (DAO - Malcentra Aŭtonoma Organizo)

Ni provas retiri monerojn de dApp Alice kaj ŝia subskribo. Ni ricevas eraron:
Lerni skribi Waves inteligentajn kontraktojn sur RIDE kaj RIDE4DAPPS. Parto 2 (DAO - Malcentra Aŭtonoma Organizo)

Ni provu retiriĝi per retiro:

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

La skripto funkcias kaj ni eltrovis la 2-an punkton!

Etapo 4. Kreu DAO kun voĉdonado

Bedaŭrinde, la RIDE-lingvo ankoraŭ ne disponigas la kapablon labori kun kolektoj (vortaroj, iteratoroj, reduktiloj ktp.). Tamen, por iuj operacioj kun plataj kolektoj ŝlosila valoro ni povas desegni sistemon por labori kun ŝnuroj, laŭe kun ŝlosiloj kaj ilia malĉifrado.

Ŝnuroj estas tre facile kunleblaj; ĉenoj povas esti apartigitaj per indeksoj.
Ni kolektu kaj analizu ĉenon kiel prova ekzemplo kaj kontrolu kiel tio influas la rezulton de la transakcio.
Ni decidis pri tio, ke Alice ne povis subskribi la Transakcion de Transdono, ĉar ĉi tiu kapablo estis blokita en @verifier por ĉi tiu tipo de transakcio.

Ni ekzercu per ŝnuroj kaj poste solvu ĉi tion.

RIDE Kordoj

La transakcio denove eblas, ni scias kiel labori kun ŝnuroj.
Lerni skribi Waves inteligentajn kontraktojn sur RIDE kaj RIDE4DAPPS. Parto 2 (DAO - Malcentra Aŭtonoma Organizo)


Entute ni havas ĉion necesan por skribi kompleksan logikon DAO dApp.

Datumaj Transakcioj

Datumaj Transakcioj:
"La maksimuma grandeco por ŝlosilo estas 100 signoj, kaj ŝlosilo povas enhavi arbitrajn Unikodajn kodpunktojn inkluzive de spacoj kaj aliaj nepreseblaj simboloj. Ŝnuraj valoroj havas limon de 32,768 100 bajtoj kaj la maksimuma nombro da eblaj eniroj en datumtransakcio estas 140. Ĝenerale, la maksimuma grandeco de datumtransakcio estas ĉirkaŭ XNUMXkb - por referenco, preskaŭ ĝuste la longeco de la teatraĵo de Ŝekspiro "Romeo kaj Julieta". '."

Ni kreas DAO kun la sekvaj kondiĉoj:
Por ke noventrepreno ricevu financadon per vokado getFunds() la subteno de almenaŭ 2 partoprenantoj - DAO-investantoj - estas bezonata. Retiriĝi ĝi eblos ĝuste tiom kiom la sumo indikita sur balotado DAO-posedantoj.

Ni faru 3 specojn de ŝlosiloj kaj aldonu logikon por labori kun saldo en 2 novaj funkcioj voĉdoni kaj getFunds:
xx...xx_ia = investantoj, disponebla saldo (voĉdono, deponejo, retiro)
xx...xx_sv = noventreprenoj, nombro da voĉoj (voĉdoni, akiriFundojn)
xx...xx_sf = noventreprenoj, nombro da voĉoj (voĉdoni, akiriFundojn)
xx...xx = publika adreso (35 signoj)

Bonvolu noti, ke en Voĉdono ni devis ĝisdatigi plurajn kampojn samtempe:

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

WriteSet permesas al ni fari plurajn rekordojn samtempe ene de unu invokeScript transakcioj.

Jen kiel ĝi aspektas en la ŝlosilvalora stokado de la DAO dApp, post kiam Bob kaj Cooper replenigis ia-deponejoj:
Lerni skribi Waves inteligentajn kontraktojn sur RIDE kaj RIDE4DAPPS. Parto 2 (DAO - Malcentra Aŭtonoma Organizo)

Nia depona funkcio iomete ŝanĝiĝis:
Lerni skribi Waves inteligentajn kontraktojn sur RIDE kaj RIDE4DAPPS. Parto 2 (DAO - Malcentra Aŭtonoma Organizo)

Nun venas la plej grava momento en la agadoj de la DAO - voĉdoni por projektoj financataj.

Bob voĉdonas por la projekto de 500000 ondetoj de Neli:

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

Lerni skribi Waves inteligentajn kontraktojn sur RIDE kaj RIDE4DAPPS. Parto 2 (DAO - Malcentra Aŭtonoma Organizo)

En la datumvendejo ni vidas ĉiujn necesajn enskribojn por la adreso de Neli:
Lerni skribi Waves inteligentajn kontraktojn sur RIDE kaj RIDE4DAPPS. Parto 2 (DAO - Malcentra Aŭtonoma Organizo)
Cooper ankaŭ voĉdonis por la Neli-projekto.
Lerni skribi Waves inteligentajn kontraktojn sur RIDE kaj RIDE4DAPPS. Parto 2 (DAO - Malcentra Aŭtonoma Organizo)

Ni rigardu la funkciokodon getFunds. Neli devas kolekti minimume 2 voĉojn por povi eltiri financon de la DAO.
Lerni skribi Waves inteligentajn kontraktojn sur RIDE kaj RIDE4DAPPS. Parto 2 (DAO - Malcentra Aŭtonoma Organizo)

Neli retiros duonon de la sumo konfidita al ŝi:

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

Lerni skribi Waves inteligentajn kontraktojn sur RIDE kaj RIDE4DAPPS. Parto 2 (DAO - Malcentra Aŭtonoma Organizo)

Ŝi sukcesas, tio estas, DAO funkcias!

Ni rigardis la procezon de kreado de DAO en la lingvo RIDE4DAPPS.
En la sekvaj partoj ni pli detale rigardos kodan refaktoradon kaj kaztestadon.

Plena versio de la kodo en 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
    }
}

Unua parto
Kodo en GitHub
Waves RIDE IDE
Anonco de la subvencioprogramo

fonto: www.habr.com

Aldoni komenton