Aprendre a escriure contractes intel·ligents Waves a RIDE i RIDE4DAPPS. Part 2 (DAO - Organització Autònoma Descentralitzada)

Aprendre a escriure contractes intel·ligents Waves a RIDE i RIDE4DAPPS. Part 2 (DAO - Organització Autònoma Descentralitzada)

Hola a tots!

В el primer part en què vam analitzar en detall com crear i treballar amb dApp (aplicació descentralitzada). Waves RIDE IDE.

Anem a provar una mica el desmuntat ara exemple.

Etapa 3. Prova del compte dApp

Aprendre a escriure contractes intel·ligents Waves a RIDE i RIDE4DAPPS. Part 2 (DAO - Organització Autònoma Descentralitzada)

Quins problemes et surten immediatament amb l'Alice? dApp Compte?
En primer lloc:
Boob i Cooper poden enviar accidentalment fons a l'adreça de dApp amb regular transferir transaccions i, per tant, no hi podreu tornar a accedir.

En segon lloc:
No restringim de cap manera que l'Alice retiri fons sense l'aprovació de Boob i/o Cooper. Ja que, presteu atenció a verificar, totes les transaccions d'Alice s'executaran.

Arreglem el segon prohibint l'Alice transferir transaccions. Despleguem l'script corregit:
Aprendre a escriure contractes intel·ligents Waves a RIDE i RIDE4DAPPS. Part 2 (DAO - Organització Autònoma Descentralitzada)

Estem intentant retirar monedes de dApp Alice i la seva signatura. Ens surt un error:
Aprendre a escriure contractes intel·ligents Waves a RIDE i RIDE4DAPPS. Part 2 (DAO - Organització Autònoma Descentralitzada)

Intentem retirar-nos mitjançant la retirada:

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

El guió funciona i hem descobert el 2n punt!

Etapa 4. Crear un DAO amb votació

Malauradament, el llenguatge RIDE encara no ofereix la possibilitat de treballar amb col·leccions (diccionaris, iteradors, reductors, etc.). Tanmateix, per a qualsevol operació amb col·leccions planes valor-clau podem dissenyar un sistema per treballar amb cadenes, en conseqüència amb claus i el seu desxifrat.

Les cadenes són molt fàcils de concatenar; les cadenes es poden separar per índexs.
Recollim i analitzem una cadena com a exemple de prova i comprovem com això afecta el resultat de la transacció.
Hem decidit que l'Alice no podia signar la transacció de transferència, ja que aquesta habilitat estava bloquejada a @verifier per a aquest tipus de transacció.

Practicem amb cordes i després resolem això.

Cordes RIDE

La transacció torna a ser possible, sabem com treballar amb cadenes.
Aprendre a escriure contractes intel·ligents Waves a RIDE i RIDE4DAPPS. Part 2 (DAO - Organització Autònoma Descentralitzada)


En total, tenim tot el necessari per escriure lògica complexa DAO dApp.

Transaccions de dades

Transaccions de dades:
"La mida màxima d'una clau és de 100 caràcters i una clau pot contenir punts de codi Unicode arbitraris, inclosos espais i altres símbols no imprimibles. Els valors de cadena tenen un límit de 32,768 bytes i el nombre màxim d'entrades possibles en la transacció de dades és de 100. En general, la mida màxima d'una transacció de dades és d'uns 140 kb, com a referència, gairebé exactament la durada de l'obra de Shakespeare "Romeu i Julieta". '.

Creem un DAO amb les següents condicions:
Perquè una startup rebi finançament trucant getFunds() es requereix el suport d'almenys 2 participants -inversors DAO-. Retirar-se serà possible exactament tant com el total indicat a votació propietaris de DAO.

Fem 3 tipus de claus i afegim lògica per treballar amb saldos en 2 noves funcions vote i getFunds:
xx...xx_ia = inversors, saldo disponible (votar, dipòsit, retirada)
xx...xx_sv = startups, nombre de vots (vota, obtén fons)
xx...xx_sf = startups, nombre de vots (vota, obtén fons)
xx…xx = adreça pública (35 caràcters)

Tingueu en compte que a Vote havíem d'actualitzar diversos camps alhora:

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

WriteSet ens permet fer diversos registres alhora en un mateix invokeScript transaccions.

Aquest és el que sembla a l'emmagatzematge de valor-clau de la DAO dApp, després que Bob i Cooper s'omplissin ia-dipòsits:
Aprendre a escriure contractes intel·ligents Waves a RIDE i RIDE4DAPPS. Part 2 (DAO - Organització Autònoma Descentralitzada)

La nostra funció de dipòsit ha canviat lleugerament:
Aprendre a escriure contractes intel·ligents Waves a RIDE i RIDE4DAPPS. Part 2 (DAO - Organització Autònoma Descentralitzada)

Ara arriba el moment més important de les activitats del DAO: votar per als projectes a finançar.

Bob vota pel projecte de 500000 wavelets de Neli:

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

Aprendre a escriure contractes intel·ligents Waves a RIDE i RIDE4DAPPS. Part 2 (DAO - Organització Autònoma Descentralitzada)

A la botiga de dades veiem totes les entrades necessàries per a l'adreça de Neli:
Aprendre a escriure contractes intel·ligents Waves a RIDE i RIDE4DAPPS. Part 2 (DAO - Organització Autònoma Descentralitzada)
Cooper també va votar pel projecte Neli.
Aprendre a escriure contractes intel·ligents Waves a RIDE i RIDE4DAPPS. Part 2 (DAO - Organització Autònoma Descentralitzada)

Fem una ullada al codi de la funció getFunds. La Neli ha de recollir un mínim de 2 vots per poder retirar fons del DAO.
Aprendre a escriure contractes intel·ligents Waves a RIDE i RIDE4DAPPS. Part 2 (DAO - Organització Autònoma Descentralitzada)

Neli va a retirar la meitat de l'import que se li ha confiat:

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

Aprendre a escriure contractes intel·ligents Waves a RIDE i RIDE4DAPPS. Part 2 (DAO - Organització Autònoma Descentralitzada)

Ella ho aconsegueix, és a dir, DAO funciona!

Hem observat el procés de creació d'un DAO en l'idioma RIDE4DAPPS.
A les parts següents, analitzarem més de prop la refactorització del codi i les proves de casos.

Versió completa del codi 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
    }
}

Primera part
Codi a GitHub
Waves RIDE IDE
Anunci del programa de subvencions

Font: www.habr.com

Compreu allotjament fiable per a llocs amb protecció DDoS, servidors VPS VDS 🔥 Compra allotjament web fiable amb protecció DDoS, servidors VPS VDS | ProHoster