Lernen, Waves Smart Contracts auf RIDE und RIDE4DAPPS zu schreiben. Teil 2 (DAO – Dezentrale Autonome Organisation)

Lernen, Waves Smart Contracts auf RIDE und RIDE4DAPPS zu schreiben. Teil 2 (DAO – Dezentrale Autonome Organisation)

Hallo an alle!

В erste Teil haben wir uns ausführlich mit der Erstellung und Arbeit mit dApp (dezentrale Anwendung) befasst Waves RIDE IDE.

Testen wir nun das zerlegte Exemplar ein wenig Beispiel.

Stufe 3. Testen des dApp-Kontos

Lernen, Waves Smart Contracts auf RIDE und RIDE4DAPPS zu schreiben. Teil 2 (DAO – Dezentrale Autonome Organisation)

Welche Probleme fallen Ihnen bei Alice sofort auf? dApp Konto?
Erstens:
Boob und Cooper senden möglicherweise versehentlich Geld an die dApp-Adresse, indem sie regelmäßig Geld verwenden privaten Transfer Transaktionen und können daher nicht mehr darauf zugreifen.

Zweitens:
Wir schränken Alice in keiner Weise ein, ohne die Zustimmung von Boob und/oder Cooper Geld abzuheben. Achten Sie auf die Überprüfung, da alle Transaktionen von Alice ausgeführt werden.

Beheben wir den zweiten Platz, indem wir Alice verbieten privaten Transfer Transaktionen. Lassen Sie uns das korrigierte Skript bereitstellen:
Lernen, Waves Smart Contracts auf RIDE und RIDE4DAPPS zu schreiben. Teil 2 (DAO – Dezentrale Autonome Organisation)

Wir versuchen, Münzen von dApp Alice und ihrer Signatur abzuheben. Wir erhalten eine Fehlermeldung:
Lernen, Waves Smart Contracts auf RIDE und RIDE4DAPPS zu schreiben. Teil 2 (DAO – Dezentrale Autonome Organisation)

Versuchen wir, über „Abheben“ abzuheben:

broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))

Das Skript funktioniert und wir haben den 2. Punkt herausgefunden!

Stufe 4. Erstellen Sie ein DAO mit Abstimmung

Leider bietet die RIDE-Sprache noch nicht die Möglichkeit, mit Sammlungen (Wörterbuchwörterbücher, Iteratoren, Reduzierer usw.) zu arbeiten. Allerdings für alle Vorgänge mit flachen Sammlungen Schlüsselwert Wir können ein System für die Arbeit mit Strings entwerfen, entsprechend mit Schlüsseln und deren Entschlüsselung.

Strings lassen sich sehr einfach verketten; Strings können durch Indizes getrennt werden.
Lassen Sie uns als Testbeispiel eine Zeichenfolge sammeln und analysieren und prüfen, wie sich dies auf das Ergebnis der Transaktion auswirkt.
Wir haben uns auf die Tatsache geeinigt, dass Alice die Übertragungstransaktion nicht signieren konnte, da diese Fähigkeit in @verifier für diese Art von Transaktion blockiert war.

Lassen Sie uns mit Strings üben und das Problem dann lösen.

RIDE-Saiten

Die Transaktion ist wieder möglich, wir wissen, wie man mit Strings arbeitet.
Lernen, Waves Smart Contracts auf RIDE und RIDE4DAPPS zu schreiben. Teil 2 (DAO – Dezentrale Autonome Organisation)


Insgesamt verfügen wir über alles Notwendige, um komplexe Logik zu schreiben DAO dApp.

Datentransaktionen

Datentransaktionen:
„Die maximale Größe eines Schlüssels beträgt 100 Zeichen und ein Schlüssel kann beliebige Unicode-Codepunkte enthalten, einschließlich Leerzeichen und anderen nicht druckbaren Symbolen.“ String-Werte haben ein Limit von 32,768 Bytes und die maximale Anzahl möglicher Einträge in einer Datentransaktion beträgt 100. Insgesamt beträgt die maximale Größe einer Datentransaktion etwa 140 KB – als Referenz, fast genau die Länge von Shakespeares Stück „Romeo und Julia“. '. ”

Wir erstellen ein DAO mit folgenden Bedingungen:
Damit ein Startup per Telefon eine Finanzierung erhält getFunds() die Unterstützung von mindestens 2 Teilnehmern – DAO-Investoren – ist erforderlich. zurückziehen Es ist genau so viel möglich, wie die auf angegebene Gesamtsumme Wählen DAO-Besitzer.

Lassen Sie uns drei Arten von Schlüsseln erstellen und Logik für die Arbeit mit Guthaben in zwei neuen Funktionen hinzufügen: vote und getFunds:
xx…xx_ia = Investoren, verfügbares Guthaben (Abstimmung, Einzahlung, Auszahlung)
xx…xx_sv = Startups, Anzahl der Stimmen (abstimmen, Gelder erhalten)
xx…xx_sf = Startups, Anzahl der Stimmen (abstimmen, Gelder erhalten)
xx…xx = öffentliche Adresse (35 Zeichen)

Bitte beachten Sie, dass wir in Abstimmung mehrere Felder gleichzeitig aktualisieren mussten:

WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),

Mit WriteSet können wir mehrere Datensätze gleichzeitig in einem erstellen invokeScript Transaktionen.

So sieht es im Schlüsselwertspeicher der DAO dApp aus, nachdem Bob und Cooper den Speicher aufgefüllt haben ia-Einlagen:
Lernen, Waves Smart Contracts auf RIDE und RIDE4DAPPS zu schreiben. Teil 2 (DAO – Dezentrale Autonome Organisation)

Unsere Einzahlungsfunktion hat sich leicht geändert:
Lernen, Waves Smart Contracts auf RIDE und RIDE4DAPPS zu schreiben. Teil 2 (DAO – Dezentrale Autonome Organisation)

Jetzt kommt der wichtigste Moment in den Aktivitäten von DAO – Abstimmung für zu finanzierende Projekte.

Bob stimmt für Nelis 500000-Wavelets-Projekt:

broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))

Lernen, Waves Smart Contracts auf RIDE und RIDE4DAPPS zu schreiben. Teil 2 (DAO – Dezentrale Autonome Organisation)

Im Datenspeicher sehen wir alle notwendigen Einträge zu Nelis Adresse:
Lernen, Waves Smart Contracts auf RIDE und RIDE4DAPPS zu schreiben. Teil 2 (DAO – Dezentrale Autonome Organisation)
Cooper stimmte auch für das Neli-Projekt.
Lernen, Waves Smart Contracts auf RIDE und RIDE4DAPPS zu schreiben. Teil 2 (DAO – Dezentrale Autonome Organisation)

Werfen wir einen Blick auf den Funktionscode getFunds. Neli muss mindestens 2 Stimmen sammeln, um Gelder vom DAO abheben zu können.
Lernen, Waves Smart Contracts auf RIDE und RIDE4DAPPS zu schreiben. Teil 2 (DAO – Dezentrale Autonome Organisation)

Neli wird die Hälfte des ihr anvertrauten Betrags abheben:

broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))

Lernen, Waves Smart Contracts auf RIDE und RIDE4DAPPS zu schreiben. Teil 2 (DAO – Dezentrale Autonome Organisation)

Sie hat Erfolg, das heißt, DAO funktioniert!

Wir haben uns den Prozess der Erstellung eines DAO in der Sprache angesehen RIDE4DAPPS.
In den folgenden Teilen werden wir uns näher mit Code-Refactoring und Case-Tests befassen.

Vollständige Version des Codes in 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
    }
}

Der erste Teil
Code auf GitHub
Waves RIDE IDE
Bekanntgabe des Förderprogramms

Source: habr.com

Kommentar hinzufügen