Aprender a escribir contratos inteligentes Waves en RIDE y RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

Aprender a escribir contratos inteligentes Waves en RIDE y RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

Hola a todos!

В primero En esta parte analizamos en detalle cómo crear y trabajar con dApp (aplicación descentralizada) en Olas PASEO IDE.

Probemos un poco el desmontado ahora. ejemplo.

Etapa 3. Prueba de la cuenta dApp

Aprender a escribir contratos inteligentes Waves en RIDE y RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

¿Qué problemas te saltan a la vista inmediatamente con Alice? dApp ¿Cuenta?
En primer lugar:
Boob y Cooper pueden enviar fondos accidentalmente a la dirección de la dApp utilizando el método regular. transferir transacciones y por lo tanto no podrá acceder a ellas nuevamente.

En segundo lugar:
No restringimos de ninguna manera que Alice retire fondos sin la aprobación de Boob y/o Cooper. Dado que, preste atención para verificar, se ejecutarán todas las transacciones de Alice.

Arreglemos el segundo baneando a Alice transferir actas. Implementemos el script corregido:
Aprender a escribir contratos inteligentes Waves en RIDE y RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

Estamos intentando retirar monedas de la dApp Alice y su firma. Obtenemos un error:
Aprender a escribir contratos inteligentes Waves en RIDE y RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

Intentemos retirar mediante retiro:

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

¡El guión funciona y descubrimos el segundo punto!

Etapa 4. Crea una DAO con votación

Desafortunadamente, el lenguaje RIDE aún no ofrece la posibilidad de trabajar con colecciones (diccionarios, iteradores, reductores, etc.). Sin embargo, para cualquier operación con cobros planos valor clave Podemos diseñar un sistema para trabajar con cadenas, de acuerdo con las claves y su descifrado.

Las cadenas son muy fáciles de concatenar; las cadenas se pueden separar mediante índices.
Recopilemos y analicemos una cadena como ejemplo de prueba y verifiquemos cómo esto afecta el resultado de la transacción.
Nos decidimos por el hecho de que Alice no pudo firmar la transacción de Transferencia, ya que esta oportunidad estaba bloqueada en @verifier para este tipo de transacción.

Practiquemos con cuerdas y luego resolvamos esto.

Cuerdas de paseo

La transacción vuelve a ser posible, sabemos cómo trabajar con cadenas.
Aprender a escribir contratos inteligentes Waves en RIDE y RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)


En total, tenemos todo lo necesario para escribir lógica compleja. Aplicación DAO.

Transacciones de datos

Transacciones de datos:
“El tamaño máximo de una clave es de 100 caracteres y una clave puede contener puntos de código Unicode arbitrarios, incluidos espacios y otros símbolos no imprimibles. Los valores de cadena tienen un límite de 32,768 bytes y el número máximo de entradas posibles en una transacción de datos es 100. En general, el tamaño máximo de una transacción de datos es de alrededor de 140 kb; como referencia, casi exactamente la longitud de la obra de Shakespeare 'Romeo y Julieta'. '."

Creamos un DAO con las siguientes condiciones:
Para que una startup reciba financiación llamando obtener fondos() Se requiere el apoyo de al menos 2 participantes (inversores DAO). retirarse será posible exactamente tanto como el total indicado en votación Propietarios de DAO.

Hagamos 3 tipos de claves y agreguemos lógica para trabajar con saldos en 2 nuevas funciones votar y obtener fondos:
xx... xx_I a = inversores, saldo disponible (voto, depósito, retiro)
xx... xx_sv = startups, número de votos (votar, obtener fondos)
xx... xx_sf = startups, número de votos (votar, obtener fondos)
xx…xx = dirección pública (35 caracteres)

Tenga en cuenta que en Votar necesitábamos actualizar varios campos a la vez:

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

WriteSet nos permite realizar varios registros a la vez dentro de un mismo invocar script actas.

Así es como se ve en el almacenamiento clave-valor de DAO dApp, después de que Bob y Cooper lo repusieron ia-depósitos:
Aprender a escribir contratos inteligentes Waves en RIDE y RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

Nuestra función de depósito ha cambiado ligeramente:
Aprender a escribir contratos inteligentes Waves en RIDE y RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

Ahora llega el momento más importante en las actividades de la DAO: votacion para proyectos a financiar.

Bob vota por el proyecto 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: []}))

Aprender a escribir contratos inteligentes Waves en RIDE y RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

En el almacén de datos vemos todas las entradas necesarias para la dirección de Neli:
Aprender a escribir contratos inteligentes Waves en RIDE y RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)
Cooper también votó a favor del proyecto Neli.
Aprender a escribir contratos inteligentes Waves en RIDE y RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

Echemos un vistazo al código de función. obtener fondos. Neli debe reunir un mínimo de 2 votos para poder retirar fondos del DAO.
Aprender a escribir contratos inteligentes Waves en RIDE y RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

Neli va a retirar la mitad del monto que le han confiado:

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

Aprender a escribir contratos inteligentes Waves en RIDE y RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

Ella tiene éxito, es decir, ¡DAO funciona!

Analizamos el proceso de creación de un DAO en el idioma. RIDE4DAPPS.
En las siguientes partes analizaremos más de cerca la refactorización de código y las pruebas de casos.

Versión completa del código en Olas 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 primera parte
Código en GitHub
Olas PASEO IDE
Anuncio del programa de subvenciones.

Fuente: habr.com

Añadir un comentario