Apprenons à écrire des contrats intelligents Waves en RIDE et RIDE4DAPPS. Partie 2 (DAO — Organisation Autonome Décentralisée)

Apprenons à écrire des contrats intelligents Waves en RIDE et RIDE4DAPPS. Partie 2 (DAO — Organisation Autonome Décentralisée)

Bonjour à tous !

Dans première partie, nous allons examiner en détail comment créer et travailler avec dApp (application décentralisée) dans Waves RIDE IDE.

Testons maintenant un peu ce qui a été analysé exemple.

Étape 3. Tester le compte dApp

Apprenons à écrire des contrats intelligents Waves en RIDE et RIDE4DAPPS. Partie 2 (DAO — Organisation Autonome Décentralisée)

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é :
Apprenons à écrire des contrats intelligents Waves en RIDE et RIDE4DAPPS. Partie 2 (DAO — Organisation Autonome Décentralisée)

Essayons de retirer des pièces d'Alice dApp avec sa signature. Nous rencontrons une erreur :
Apprenons à écrire des contrats intelligents Waves en RIDE et RIDE4DAPPS. Partie 2 (DAO — Organisation Autonome Décentralisée)

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.
Apprenons à écrire des contrats intelligents Waves en RIDE et RIDE4DAPPS. Partie 2 (DAO — Organisation Autonome Décentralisée)


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 :
Apprenons à écrire des contrats intelligents Waves en RIDE et RIDE4DAPPS. Partie 2 (DAO — Organisation Autonome Décentralisée)

La fonction de dépôt a légèrement changé :
Apprenons à écrire des contrats intelligents Waves en RIDE et RIDE4DAPPS. Partie 2 (DAO — Organisation Autonome Décentralisée)

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: []}))

Apprenons à écrire des contrats intelligents Waves en RIDE et RIDE4DAPPS. Partie 2 (DAO — Organisation Autonome Décentralisée)

Dans le stockage de données, nous voyons tous les enregistrements nécessaires pour l'adresse de Neli :
Apprenons à écrire des contrats intelligents Waves en RIDE et RIDE4DAPPS. Partie 2 (DAO — Organisation Autonome Décentralisée)
Cooper a également voté pour le projet Neli.
Apprenons à écrire des contrats intelligents Waves en RIDE et RIDE4DAPPS. Partie 2 (DAO — Organisation Autonome Décentralisée)

Jetons un œil au code de la fonction getFunds. Neli doit récolter au moins 2 voix pour pouvoir retirer des fonds du DAO.
Apprenons à écrire des contrats intelligents Waves en RIDE et RIDE4DAPPS. Partie 2 (DAO — Organisation Autonome Décentralisée)

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: []}))

Apprenons à écrire des contrats intelligents Waves en RIDE et RIDE4DAPPS. Partie 2 (DAO — Organisation Autonome Décentralisée)

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 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
    }
}

Première partie
Le code sur GitHub
Waves RIDE IDE
Annonce du programme de subventions

Source : habr.com

Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS 🔥 Acheter un hébergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster