Hallo iedereen!
В
Laten we de gedemonteerde nu een beetje testen
Fase 3. Het dApp-account testen
Welke problemen vallen je meteen op met Alice? dapper Account?
Во-первых:
Boob en Cooper kunnen per ongeluk geld naar het dApp-adres sturen via regulier overdracht transacties en zullen er dus geen toegang toe hebben.Во-вторых:
We beperken Alice op geen enkele manier in het opnemen van geld zonder de goedkeuring van Boob en/of Cooper. Let op: alle transacties van Alice worden uitgevoerd.
Laten we het tweede probleem oplossen door Alice te verbannen overdracht transacties. Laten we het gecorrigeerde script implementeren:

We proberen munten van dApp Alice en haar handtekening op te nemen. We krijgen een foutmelding:
Laten we proberen op te nemen via intrekken:
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 ontdekt!
Fase 4. Creëer een DAO met stemming
Helaas biedt de RIDE-taal nog niet de mogelijkheid om met verzamelingen te werken (woordenboeken, iterators, reducers, enz.). Echter, voor alle operaties met platte collecties sleutel waarde we kunnen een systeem ontwerpen voor het werken met strings, dus met sleutels en hun decodering.
Tekenreeksen zijn heel gemakkelijk samen te voegen; tekenreeksen kunnen worden gescheiden door indexen.
Laten we een string verzamelen en parseren als testvoorbeeld en controleren hoe dit de uitkomst van de transactie beïnvloedt.
We kwamen tot de conclusie dat Alice de overdrachtstransactie niet kon ondertekenen, omdat deze mogelijkheid voor dit type transactie in @verifier was geblokkeerd.
Laten we oefenen met snaren en dit dan oplossen.
RIDE-snaren
De transactie is weer mogelijk, wij weten hoe we met strings moeten werken.

In totaal hebben we alles wat nodig is om complexe logica te schrijven DAO dApp.
Gegevenstransacties
Gegevenstransacties:
“De maximale grootte voor een sleutel is 100 tekens, en een sleutel kan willekeurige Unicode-codepunten bevatten, inclusief spaties en andere niet-afdrukbare symbolen. Tekenreekswaarden hebben een limiet van 32,768 bytes en het maximale aantal mogelijke vermeldingen bij datatransacties is 100. In totaal bedraagt de maximale grootte van een datatransactie ongeveer 140 kb – ter referentie: vrijwel precies de lengte van Shakespeares toneelstuk 'Romeo en Julia'. '. ”
We creëren een DAO met de volgende voorwaarden:
Zodat een startup financiering kan ontvangen door te bellen getFunds() de steun van minimaal 2 deelnemers – DAO-investeerders – is vereist. terugtrekken het zal precies zoveel mogelijk zijn als het totaal aangegeven op stemmen DAO-eigenaren.
Laten we 3 soorten sleutels maken en logica toevoegen voor het werken met saldi in 2 nieuwe functies stemmen en geld ophalen:
xx...xx_IA = investeerders, beschikbaar saldo (stemming, storting, terugtrekking)
xx...xx_sv = startups, aantal stemmen (stemmen, getFunds)
xx...xx_sf = startups, aantal stemmen (stemmen, getFunds)
xx…xx = openbaar adres (35 tekens)
Houd er rekening mee dat we bij Stemmen meerdere velden tegelijk moesten bijwerken:
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),
Met WriteSet kunnen we binnen één record meerdere records tegelijk maken invokeScript transacties.
Zo ziet het eruit in de sleutelwaardeopslag van de DAO dApp, nadat Bob en Cooper hebben aangevuld ia-stortingen:
Onze stortingsfunctie is enigszins veranderd:
Nu komt het belangrijkste moment in de activiteiten van de DAO: stemmen voor te financieren projecten.
Bob stemt voor Neli's 500000 wavelets-project:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
In de gegevensopslag zien we alle benodigde gegevens voor Neli's adres:
Cooper stemde ook voor het Neli-project.
Laten we eens kijken naar de functiecode krijg fondsen. Neli moet minimaal 2 stemmen verzamelen om geld van de DAO te kunnen opnemen.
Neli gaat de helft van het haar toevertrouwde bedrag opnemen:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))
Het lukt haar, dat wil zeggen, DAO werkt!
We hebben gekeken naar het proces van het maken van een DAO in de taal RIDE4DAPPS.
In de volgende delen gaan we dieper in op coderefactoring en case-testen.
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: www.habr.com