
Hallo allemaal!
In In deze delen hebben we gedetailleerd besproken hoe we dApp (gedecentraliseerde applicatie) kunnen maken en ermee kunnen werken in .
Laten we nu even de besproken punten testen. .
Stap 3. Testen van het dApp-account

Welke problemen springen meteen in het oog met Alice? dApp Account?
Ten eerste:
Boob en Cooper kunnen per ongeluk middelen naar het dApp-adres verzenden via een gewone transfer transactie en kunnen deze daardoor niet meer terugkrijgen.Ten tweede:
We beperken Alice niet in het opnemen van middelen zonder goedkeuring van Boob of Cooper. Merk op dat, zoals vermeld bij verify, alle transacties van Alice zullen worden uitgevoerd.
Laten we het tweede probleem oplossen door Alice transfer transacties te verbieden. We implementeren het gecorrigeerde script:


We proberen munten op te nemen van de dApp Alice met haar handtekening. We krijgen een foutmelding:

We proberen het via withdraw:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))Het script werkt en we hebben het tweede punt opgelost!
Stap 4. Creëren van een DAO met stemmen
Helaas biedt de RIDE-taal momenteel geen mogelijkheden voor het werken met collecties (woordenboeken-van-woordenboeken, iterators, reducers, enzovoort). Maar voor alle bewerkingen met platte collecties key-value kunnen we een systeem ontwerpen dat met strings werkt, overeenkomstig met sleutels en hun ontcijfering.
Strings zijn heel eenvoudig samen te voegen, en strings kunnen worden gesplitst op indexen.
Laten we als testvoorbeeld een string samenstellen en ontleden en controleren hoe dit de uitkomst van de transactie beïnvloedt.
We zijn gestopt bij het feit dat Alice de Transfer-transactie niet kon ondertekenen, omdat deze mogelijkheid was geblokkeerd in @verifier voor dit type transacties.
Laten we oefenen met strings en dit later toestaan.
RIDE Strings
De transactie is opnieuw mogelijk; we kunnen met strings werken.


Dus hebben we alles wat nodig is om complexe logica te schrijven. DAO dApp.
Data Transactions
Data Transactions:
“De maximale grootte voor een sleutel is 100 karakters, en een sleutel kan willekeurige Unicode-codepunten bevatten, inclusief spaties en andere niet-afdrukbare symbolen. Stringwaarden hebben een limiet van 32.768 bytes en het maximum aantal mogelijke items in een datatransactie is 100. Over het geheel genomen is de maximale grootte van een datatransactie ongeveer 140 kb - ter referentie, bijna precies de lengte van Shakespeares toneelstuk ‘Romeo en Julia’.”
Laten we een DAO creëren met de volgende voorwaarden:
Om financiering voor de start-up te verkrijgen door getFunds() is de steun van minimaal 2 deelnemers — investeerders van de DAO — vereist. Toon Er kan precies zoveel worden opgevraagd als in totaal is aangegeven in het stemmen door de eigenaren van de DAO.
Laten we 3 soorten sleutels maken en logica toevoegen voor het werken met saldi in 2 nieuwe functies: vote en getFunds:
xx…xx_ia = investeerders, beschikbaar saldo (stem, storting, opname)
xx…xx_sv = startups, aantal stemmen (stem, getFunds)
xx…xx_sf = startups, aantal stemmen (stem, getFunds)
xx…xx = openbaar adres (35 tekens)
Let op dat we in Vote meerdere velden moesten bijwerken:
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),WriteSet stelt ons in staat om meerdere invoeren tegelijk te maken binnen één invokeScript transactie.
Zo ziet het eruit in de key-value opslag van de DAO dApp, nadat Bob en Cooper hun ia-stortingen:

De stortingsfunctie is iets veranderd:

Nu komt het belangrijkste moment in de activiteiten van de DAO — stemmen voor projecten voor financiering.
Bob stemt op project Neli voor 500000 wavelets:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
In de datastore zien we alle benodigde invoer voor adres Neli:

Cooper heeft ook gestemd op project Neli.

Laten we eens kijken naar de code van de functie getFunds. Neli moet minimaal 2 stemmen verzamelen om in staat te zijn om geld uit de DAO op te nemen.

Neli is van plan om de helft van het haar toegewezen bedrag op te nemen:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))
Dit lukt haar, wat betekent dat de DAO werkt!
We hebben het proces voor het creëren van een DAO in de taal RIDE4DAPPS.
In de volgende delen zullen we dieper ingaan op het refactoren van de code en het testen van scenario's.
De volledige versie van de code 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
}
}
Bron: habr.com
