Aprende a escribir contratos intelixentes de Waves en RIDE e RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

Aprende a escribir contratos intelixentes de Waves en RIDE e RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

Ola a todos!

В o primeiro parte analizamos en detalle como crear e traballar con dApp (aplicación descentralizada). Waves RIDE IDE.

Probamos un pouco o desmontado agora exemplo.

Fase 3. Proba da conta dApp

Aprende a escribir contratos intelixentes de Waves en RIDE e RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

Que problemas che saltan inmediatamente con Alice? dApp Conta?
En primeiro lugar:
Boob e Cooper poden enviar accidentalmente fondos ao enderezo dApp usando regular descargar transaccións e, polo tanto, non poderá acceder a elas.

En segundo lugar:
Non restrinximos a Alice de ningún xeito a retirar fondos sen a aprobación de Boob e/ou Cooper. Xa que, preste atención a verificar, todas as transaccións de Alice serán executadas.

Imos corrixir o segundo prohibindo a Alicia descargar transaccións. Imos implementar o script corrixido:
Aprende a escribir contratos intelixentes de Waves en RIDE e RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

Estamos tentando retirar moedas de dApp Alice e a súa sinatura. Recibimos un erro:
Aprende a escribir contratos intelixentes de Waves en RIDE e RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

Intentemos retirar a través de retirar:

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

O guión funciona e descubrimos o 2o punto!

Etapa 4. Crear un DAO con votación

Desafortunadamente, a linguaxe RIDE aínda non ofrece a posibilidade de traballar con coleccións (dicionarios de dicionarios, iteradores, redutores, etc.). Non obstante, para calquera operación con coleccións planas clave-valor podemos deseñar un sistema para traballar con cadeas, segundo as claves e o seu descifrado.

As cadeas son moi fáciles de concatenar; as cadeas pódense separar por índices.
Recollemos e analicemos unha cadea como exemplo de proba e comprobemos como afecta isto ao resultado da transacción.
Decidimos que Alice non podía asinar a transacción de transferencia, xa que esta capacidade estaba bloqueada en @verifier para este tipo de transacción.

Practiquemos con cordas e despois resolvamos isto.

Cordas RIDE

A transacción é posible de novo, sabemos como traballar con cadeas.
Aprende a escribir contratos intelixentes de Waves en RIDE e RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)


En total, temos todo o necesario para escribir lóxica complexa DAO dApp.

Transaccións de datos

Transaccións de datos:
"O tamaño máximo dunha chave é de 100 caracteres e unha clave pode conter puntos de código Unicode arbitrarios, incluíndo espazos e outros símbolos non imprimibles. Os valores das cadeas teñen un límite de 32,768 bytes e o número máximo de entradas posibles na transacción de datos é de 100. En xeral, o tamaño máximo dunha transacción de datos é duns 140 kb; como referencia, case exactamente a duración da obra de Shakespeare "Romeo e Xulieta". '."

Creamos un DAO coas seguintes condicións:
Para que unha startup reciba financiamento chamando conseguir fondos() é necesario o apoio de polo menos 2 participantes - investidores DAO -. Saída será posible exactamente tanto como o total indicado en votación Propietarios de DAO.

Fagamos 3 tipos de claves e engademos lóxica para traballar con saldos en dúas novas funcións votar e obterFunds:
xx...xx_ia = inversores, saldo dispoñible (votar, depositar, retirar)
xx...xx_sv = startups, número de votos (votar, conseguir fondos)
xx...xx_sf = startups, número de votos (votar, conseguir fondos)
xx…xx = enderezo público (35 caracteres)

Ten en conta que en Vote necesitabamos actualizar varios campos á vez:

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

WriteSet permítenos facer varios rexistros á vez nun mesmo invokeScript transaccións.

Así se ve no almacenamento de clave-valor da DAO dApp, despois de que Bob e Cooper se repoñan ia-Depósitos:
Aprende a escribir contratos intelixentes de Waves en RIDE e RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

A nosa función de depósito cambiou lixeiramente:
Aprende a escribir contratos intelixentes de Waves en RIDE e RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

Agora chega o momento máis importante das actividades da DAO: vota para os proxectos a financiar.

Bob vota polo proxecto 500000 wavelets de Neli:

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

Aprende a escribir contratos intelixentes de Waves en RIDE e RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

No almacén de datos vemos todas as entradas necesarias para o enderezo de Neli:
Aprende a escribir contratos intelixentes de Waves en RIDE e RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)
Cooper tamén votou polo proxecto Neli.
Aprende a escribir contratos intelixentes de Waves en RIDE e RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

Vexamos o código da función obter fondos. Neli debe recoller un mínimo de 2 votos para poder retirar fondos do DAO.
Aprende a escribir contratos intelixentes de Waves en RIDE e RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

Neli vai retirar a metade da cantidade que se lle encomenda:

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

Aprende a escribir contratos intelixentes de Waves en RIDE e RIDE4DAPPS. Parte 2 (DAO - Organización Autónoma Descentralizada)

Ela ten éxito, é dicir, DAO funciona!

Observamos o proceso de creación dun DAO na lingua RIDE4DAPPS.
Nas seguintes partes analizaremos a refactorización de código e as probas de casos.

Versión completa do código 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
    }
}

Primeira parte
Código en GitHub
Waves RIDE IDE
Anuncio do programa de subvencións

Fonte: www.habr.com

Engadir un comentario