Imparare a scrivere contratti intelligenti Waves su RIDE e RIDE4DAPPS. Parte 2 (DAO - Organizzazione Autonoma Decentralizzata)

Imparare a scrivere contratti intelligenti Waves su RIDE e RIDE4DAPPS. Parte 2 (DAO - Organizzazione Autonoma Decentralizzata)

Ciao a tutti!

В prima parte abbiamo esaminato in dettaglio come creare e lavorare con dApp (applicazione decentralizzata). Onde RIDE IDE.

Adesso testiamo un po' quello smontato esempio.

Fase 3. Testare l'account dApp

Imparare a scrivere contratti intelligenti Waves su RIDE e RIDE4DAPPS. Parte 2 (DAO - Organizzazione Autonoma Decentralizzata)

Quali problemi ti saltano subito all'occhio con Alice? Däpp Account?
Primo:
Boob e Cooper potrebbero inviare accidentalmente fondi all'indirizzo della dApp utilizzando la modalità normale trasferimento transazioni e quindi non sarà possibile accedervi nuovamente.

Во-вторых:
Non limitiamo in alcun modo ad Alice il prelievo di fondi senza l'approvazione di Boob e/o Cooper. Poiché, fai attenzione a verificare, tutte le transazioni da Alice verranno eseguite.

Risolviamo il 2° bannando Alice trasferimento transazioni. Distribuiamo lo script corretto:
Imparare a scrivere contratti intelligenti Waves su RIDE e RIDE4DAPPS. Parte 2 (DAO - Organizzazione Autonoma Decentralizzata)

Stiamo provando a prelevare monete dalla dApp Alice e dalla sua firma. Otteniamo un errore:
Imparare a scrivere contratti intelligenti Waves su RIDE e RIDE4DAPPS. Parte 2 (DAO - Organizzazione Autonoma Decentralizzata)

Proviamo a ritirare tramite ritiro:

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

La sceneggiatura funziona e abbiamo capito il 2° punto!

Fase 4. Crea una DAO con votazione

Sfortunatamente, il linguaggio RIDE non offre ancora la possibilità di lavorare con raccolte (dizionari dizionari, iteratori, riduttori, ecc.). Tuttavia, per eventuali operazioni con incassi flat valore-chiave possiamo progettare un sistema per lavorare con le stringhe, di conseguenza con le chiavi e la loro decrittazione.

Le stringhe sono molto facili da concatenare; le stringhe possono essere separate da indici.
Raccogliamo e analizziamo una stringa come esempio di test e controlliamo come ciò influisce sull'esito della transazione.
Abbiamo deciso che Alice non potesse firmare la transazione di trasferimento, poiché questa capacità era bloccata in @verifier per questo tipo di transazione.

Facciamo pratica con le stringhe e poi risolviamo il problema.

Corde RIDE

La transazione è di nuovo possibile, sappiamo come lavorare con le stringhe.
Imparare a scrivere contratti intelligenti Waves su RIDE e RIDE4DAPPS. Parte 2 (DAO - Organizzazione Autonoma Decentralizzata)


In totale, abbiamo tutto il necessario per scrivere una logica complessa DAO dApp.

Transazioni di dati

Transazioni di dati:
“La dimensione massima per una chiave è di 100 caratteri e una chiave può contenere punti di codice Unicode arbitrari inclusi spazi e altri simboli non stampabili. I valori stringa hanno un limite di 32,768 byte e il numero massimo di voci possibili nella transazione dati è 100. Nel complesso, la dimensione massima di una transazione dati è di circa 140 kb — per riferimento, quasi esattamente la lunghezza dell'opera di Shakespeare "Romeo e Giulietta" '."

Creiamo una DAO con le seguenti condizioni:
Affinché una startup possa ricevere finanziamenti chiamando ottienifondi() è richiesto il supporto di almeno 2 partecipanti - investitori DAO. ritirarsi sarà possibile esattamente quanto il totale indicato su voto Proprietari DAO.

Creiamo 3 tipi di chiavi e aggiungiamo la logica per lavorare con i saldi in 2 nuove funzioni vote e getFunds:
xx…xx_ia = investitori, saldo disponibile (voto, deposito, ritiro)
xx…xx_sv = startup, numero di voti (vota, ottieni fondi)
xx…xx_sf = startup, numero di voti (vota, ottieni fondi)
xx…xx = indirizzo pubblico (35 caratteri)

Tieni presente che in Vota dovevamo aggiornare più campi contemporaneamente:

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

WriteSet ci consente di creare più record contemporaneamente all'interno di uno invocaScript transazioni.

Questo è ciò che appare nell'archiviazione dei valori-chiave della dApp DAO, dopo il rifornimento di Bob e Cooper ia-depositi:
Imparare a scrivere contratti intelligenti Waves su RIDE e RIDE4DAPPS. Parte 2 (DAO - Organizzazione Autonoma Decentralizzata)

La nostra funzione di deposito è leggermente cambiata:
Imparare a scrivere contratti intelligenti Waves su RIDE e RIDE4DAPPS. Parte 2 (DAO - Organizzazione Autonoma Decentralizzata)

Ora arriva il momento più importante nelle attività della DAO - voto per i progetti da finanziare.

Bob vota per il progetto da 500000 wavelet di Neli:

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

Imparare a scrivere contratti intelligenti Waves su RIDE e RIDE4DAPPS. Parte 2 (DAO - Organizzazione Autonoma Decentralizzata)

Nell'archivio dati vediamo tutte le voci necessarie per l'indirizzo di Neli:
Imparare a scrivere contratti intelligenti Waves su RIDE e RIDE4DAPPS. Parte 2 (DAO - Organizzazione Autonoma Decentralizzata)
Anche Cooper ha votato a favore del progetto Neli.
Imparare a scrivere contratti intelligenti Waves su RIDE e RIDE4DAPPS. Parte 2 (DAO - Organizzazione Autonoma Decentralizzata)

Diamo un'occhiata al codice della funzione getFunds. Neli deve raccogliere un minimo di 2 voti per poter prelevare fondi dalla DAO.
Imparare a scrivere contratti intelligenti Waves su RIDE e RIDE4DAPPS. Parte 2 (DAO - Organizzazione Autonoma Decentralizzata)

Neli ritirerà la metà della somma affidatale:

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

Imparare a scrivere contratti intelligenti Waves su RIDE e RIDE4DAPPS. Parte 2 (DAO - Organizzazione Autonoma Decentralizzata)

Ci riesce, cioè DAO funziona!

Abbiamo esaminato il processo di creazione di un DAO nel linguaggio RIDE4DAPPS.
Nelle parti seguenti daremo uno sguardo più approfondito al refactoring del codice e al test dei casi.

Versione completa del codice in Onde 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
    }
}

La prima parte
Codice su GitHub
Onde RIDE IDE
Annuncio del programma di sovvenzione

Fonte: habr.com

Aggiungi un commento