Hola a todos!
В
Probemos un poco el desmontado ahora.
Etapa 3. Prueba de la cuenta dApp
¿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:

Estamos intentando retirar monedas de la dApp Alice y su firma. Obtenemos un error:
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.

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:
Nuestra función de depósito ha cambiado ligeramente:
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: []}))
En el almacén de datos vemos todas las entradas necesarias para la dirección de Neli:
Cooper también votó a favor del proyecto Neli.
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.
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: []}))
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
# 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
}
}
Fuente: habr.com