
¡Hola a todos!
En parte hemos explorado en detalle cómo crear y trabajar con dApp (aplicación descentralizada) en .
Vamos a probar un poco lo que hemos analizado .
Etapa 3. Prueba de la cuenta dApp

¿Qué problemas aparecen de inmediato con Alice? dApp Cuenta?
Primero:
Boob y Cooper pueden accidentalmente enviar fondos a la dirección dApp mediante una transferencia transacción normal y, por lo tanto, no podrán volver a acceder a ellos.Segundo:
No limitamos a Alice en la retirada de fondos sin acuerdo con Boob y/o Cooper. Como, presten atención a verify, todas las transacciones de Alice se ejecutarán.
Vamos a corregir el segundo punto, prohibiendo a Alice transferencia transacciones. Desplegamos el script corregido:


Intentamos retirar monedas de dApp con la firma de Alice. Obtenemos un error:

Intentamos retirar a través de withdraw:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))¡El script funciona y hemos resuelto el segundo punto!
Etapa 4. Creamos un DAO con votación
Desafortunadamente, el lenguaje RIDE aún no tiene capacidades para trabajar con colecciones (diccionarios-anidadores, iteradores, reductores, etc.). Sin embargo, para cualquier operación con colecciones planas key-value podemos diseñar un sistema para trabajar con cadenas, correspondiente a las claves y su descifrado.
Es muy fácil concatenar cadenas; se pueden dividir por índices.
Tomemos ahora un ejemplo de prueba, construyamos y analicemos una cadena y veamos cómo afecta al resultado de la transacción.
Nos quedamos en que Alice no pudo firmar la transacción de transferencia ya que esta posibilidad estaba bloqueada en @verifier para ese tipo de transacciones.
Vamos a practicar con cadenas y luego permitiremos esto.
Cadenas RIDE
La transacción es posible nuevamente; podemos trabajar con cadenas.


En resumen, tenemos todo lo necesario para escribir lógica compleja dApp DAO.
Transacciones de datos
Transacciones de datos:
“El tamaño máximo para 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 la 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; para referencia, casi exactamente la longitud de la obra 'Romeo y Julieta' de Shakespeare.”
Creamos un DAO con las siguientes condiciones:
Para que una startup obtenga financiamiento al llamar getFunds() se requiere el apoyo de al menos 2 participantes: inversores DAO. Mostrar se permitirán tantas como se indiquen en la votación propietarios de DAO.
Creemos 3 tipos de claves y agreguemos la lógica para trabajar con saldos en 2 nuevas funciones: vote y getFunds:
xx…xx_ia = inversores, saldo disponible (vote, deposit, withdrawal)
xx…xx_sv = startups, cantidad de votos (vote, getFunds)
xx…xx_sf = startups, cantidad de votos (vote, getFunds)
xx…xx = dirección pública (35 caracteres)
Noten que en Vote necesitamos actualizar varios campos a la vez:
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),WriteSet nos permite hacer varias entradas dentro de una sola invokeScript transacción.
Así es como se ve en el almacén clave-valor de la dApp DAO, después de que Bob y Cooper hicieron depósitos. ia-depósitos:

La función de depósito ha cambiado ligeramente:

Ahora llega el momento más importante en la actividad del DAO — votación por proyectos para financiamiento.
Bob vota a favor del proyecto Neli por 500000 wavelets:
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 Neli:

Cooper también votó a favor del proyecto Neli.

Echemos un vistazo al código de la función getFunds.Neli debe reunir al menos 2 votos para poder retirar fondos del DAO.

Neli planea retirar la mitad de la cantidad que se le confió:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))
Ella lo logra, ¡lo que significa que el DAO funciona!
Hemos revisado el proceso de creación del DAO en el lenguaje RIDE4DAPPS..
En las próximas partes, nos enfocaremos más en el refactorizado del código y las pruebas de casos.
La 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
