
Bonjour à tous !
Dans partie, nous allons examiner en détail comment créer et travailler avec dApp (application décentralisée) dans .
Testons maintenant un peu ce qui a été analysé .
Étape 3. Tester le compte dApp

Quels problèmes sont immédiatement visibles avec Alice dApp Compte ?
Tout d'abord :
Boob et Cooper peuvent accidentellement envoyer des fonds à l'adresse dApp en utilisant une simple transfert transaction et, de ce fait, ne pourront pas y accéder à nouveau.Deuxièmement :
Nous ne limitons en aucun cas Alice dans le retrait de fonds sans accord avec Boob ou (et) Cooper. En effet, notez que toutes les transactions d'Alice seront exécutées.
Corrigeons le 2ème point en interdisant à Alice transfert les transactions. Déployons le script corrigé :


Essayons de retirer des pièces d'Alice dApp avec sa signature. Nous rencontrons une erreur :

Tentons de retirer via withdraw :
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))Le script fonctionne et nous avons compris le 2ème point !
Étape 4. Création d'un DAO avec vote
Malheureusement, le langage RIDE ne permet pas encore de travailler avec des collections (dictionnaires de dictionnaires, itérateurs, réducteurs, etc.). Cependant, pour toute opération avec des collections plates clé-valeur nous pouvons concevoir un système de traitement de chaînes, en conséquence avec les clés et leur décryptage.
Les chaînes peuvent être concaténées très facilement, et elles peuvent être divisées par indices.
Prenons un exemple de test pour rassembler et analyser une chaîne et vérifier comment cela affecte le résultat de la transaction.
Nous avons constaté qu'Alice ne pouvait pas signer la transaction de transfer, car cette possibilité était bloquée dans @verifier pour ce type de transactions.
Exerçons-nous avec des chaînes et ensuite autorisons cela.
RIDE Strings
La transaction est à nouveau possible, nous savons travailler avec des chaînes.


En résumé, nous avons tout ce qu'il faut pour écrire une logique complexe DAO dApp.
Transactions de données
Transactions de données :
« La taille maximale d'une clé est de 100 caractères, et une clé peut contenir des points de code Unicode arbitraires, y compris des espaces et d'autres symboles non imprimables. Les valeurs de chaîne ont une limite de 32 768 octets et le nombre maximum d'entrées possibles dans une transaction de données est de 100. En résumé, la taille maximale d'une transaction de données est d'environ 140 Ko - pour référence, presque exactement la longueur de la pièce de Shakespeare 'Roméo et Juliette'. »
Créons un DAO avec les conditions suivantes :
Pour qu'une startup obtienne un financement en appelant getFunds() le soutien d'au moins 2 participants - investisseurs du DAO est nécessaire. Afficher le nombre de participants sera exactement celui que vous avez indiqué au total dans le vote propriétaires de DAO.
Créons 3 types de clés et ajoutons la logique de gestion des soldes dans 2 nouvelles fonctions : vote et getFunds :
xx…xx_ia = investisseurs, solde disponible (vote, dépôt, retrait)
xx…xx_sv = startups, nombre de votes (vote, getFunds)
xx…xx_sf = startups, nombre de votes (vote, getFunds)
xx…xx = adresse publique (35 caractères)
Notez qu'il nous a fallu mettre à jour plusieurs champs dans Vote :
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),WriteSet nous permet de faire plusieurs enregistrements dans le cadre d'une invokeScript transaction.
Voici à quoi cela ressemble dans le stockage clé-valeur de l'application DAO dApp, après que Bob et Cooper aient complété ia-dépôts :

La fonction de dépôt a légèrement changé :

Nous voici face à un moment crucial de l'activité du DAO — vote pour les projets à financer.
Bob vote pour le projet Neli pour 500000 wavelets :
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
Dans le stockage de données, nous voyons tous les enregistrements nécessaires pour l'adresse de Neli :

Cooper a également voté pour le projet Neli.

Jetons un œil au code de la fonction getFunds. Neli doit récolter au moins 2 voix pour pouvoir retirer des fonds du DAO.

Neli s'apprête à retirer la moitié de la somme qui lui a été confiée :
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))
Elle réussit, ce qui signifie que le DAO fonctionne !
Nous avons examiné le processus de création de DAO dans le langage RIDE4DAPPS.
Dans les prochaines parties, nous aborderons plus en détail le refactoring du code et les tests de cas.
La version complète du code se trouve dans
# 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
}
}
Source : habr.com
