Ciao a tutti!
В
Adesso testiamo un po' quello smontato
Fase 3. Testare l'account dApp
Quali problemi ti saltano subito all'occhio con Alice? Däpp Account?
Primo:
Boob e Cooper potrebbero inviare accidentalmente fondi all'indirizzo della dApp utilizzando la modalità normale trasferimento transazioni e quindi non sarà possibile accedervi nuovamente.Во-вторых:
Non limitiamo in alcun modo ad Alice il prelievo di fondi senza l'approvazione di Boob e/o Cooper. Poiché, fai attenzione a verificare, tutte le transazioni da Alice verranno eseguite.
Risolviamo il 2° bannando Alice trasferimento transazioni. Distribuiamo lo script corretto:

Stiamo provando a prelevare monete dalla dApp Alice e dalla sua firma. Otteniamo un errore:
Proviamo a ritirare tramite ritiro:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))
La sceneggiatura funziona e abbiamo capito il 2° punto!
Fase 4. Crea una DAO con votazione
Sfortunatamente, il linguaggio RIDE non offre ancora la possibilità di lavorare con raccolte (dizionari dizionari, iteratori, riduttori, ecc.). Tuttavia, per eventuali operazioni con incassi flat valore-chiave possiamo progettare un sistema per lavorare con le stringhe, di conseguenza con le chiavi e la loro decrittazione.
Le stringhe sono molto facili da concatenare; le stringhe possono essere separate da indici.
Raccogliamo e analizziamo una stringa come esempio di test e controlliamo come ciò influisce sull'esito della transazione.
Abbiamo deciso che Alice non potesse firmare la transazione di trasferimento, poiché questa capacità era bloccata in @verifier per questo tipo di transazione.
Facciamo pratica con le stringhe e poi risolviamo il problema.
Corde RIDE
La transazione è di nuovo possibile, sappiamo come lavorare con le stringhe.

In totale, abbiamo tutto il necessario per scrivere una logica complessa DAO dApp.
Transazioni di dati
Transazioni di dati:
“La dimensione massima per una chiave è di 100 caratteri e una chiave può contenere punti di codice Unicode arbitrari inclusi spazi e altri simboli non stampabili. I valori stringa hanno un limite di 32,768 byte e il numero massimo di voci possibili nella transazione dati è 100. Nel complesso, la dimensione massima di una transazione dati è di circa 140 kb — per riferimento, quasi esattamente la lunghezza dell'opera di Shakespeare "Romeo e Giulietta" '."
Creiamo una DAO con le seguenti condizioni:
Affinché una startup possa ricevere finanziamenti chiamando ottienifondi() è richiesto il supporto di almeno 2 partecipanti - investitori DAO. ritirarsi sarà possibile esattamente quanto il totale indicato su voto Proprietari DAO.
Creiamo 3 tipi di chiavi e aggiungiamo la logica per lavorare con i saldi in 2 nuove funzioni vote e getFunds:
xx…xx_ia = investitori, saldo disponibile (voto, deposito, ritiro)
xx…xx_sv = startup, numero di voti (vota, ottieni fondi)
xx…xx_sf = startup, numero di voti (vota, ottieni fondi)
xx…xx = indirizzo pubblico (35 caratteri)
Tieni presente che in Vota dovevamo aggiornare più campi contemporaneamente:
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),
WriteSet ci consente di creare più record contemporaneamente all'interno di uno invocaScript transazioni.
Questo è ciò che appare nell'archiviazione dei valori-chiave della dApp DAO, dopo il rifornimento di Bob e Cooper ia-depositi:
La nostra funzione di deposito è leggermente cambiata:
Ora arriva il momento più importante nelle attività della DAO - voto per i progetti da finanziare.
Bob vota per il progetto da 500000 wavelet di Neli:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
Nell'archivio dati vediamo tutte le voci necessarie per l'indirizzo di Neli:
Anche Cooper ha votato a favore del progetto Neli.
Diamo un'occhiata al codice della funzione getFunds. Neli deve raccogliere un minimo di 2 voti per poter prelevare fondi dalla DAO.
Neli ritirerà la metà della somma affidatale:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))
Ci riesce, cioè DAO funziona!
Abbiamo esaminato il processo di creazione di un DAO nel linguaggio RIDE4DAPPS.
Nelle parti seguenti daremo uno sguardo più approfondito al refactoring del codice e al test dei casi.
Versione completa del codice in
# 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
}
}
Fonte: habr.com