
Hej alle sammen!
I I delte grundigt, hvordan man opretter og arbejder med en dApp (decentraliseret applikation) i .
Lad os nu teste det, vi har gennemgÄet .
Trin 3. Testning af dApp-kontoen

Hvilke problemer dukker straks op med Alice? dApp Konto?
For det fĂžrste:
Boob og Cooper kan utilsigtet sende midler til dApp-adressen via en almindelig overfÞrsel transaktion og derved ikke fÄ adgang til dem igen.For det andet:
Vi begrĂŠnser ikke Alice i at hĂŠve midler uden aftale med Boob eller(og) Cooper. Som bemĂŠrket, vil alle transaktioner fra Alice blive udfĂžrt.
Lad os rette nummer 2 ved at forbyde Alice overfĂžrsel transaktioner. Vi deployer det rettede script:

ïżŒ
Vi prÞver at hÊve mÞnter fra dApp med Alice og hendes underskrift. Vi fÄr en fejl:

Vi prĂžver at hĂŠve via withdraw:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))Scriptet fungerer, og vi har styr pÄ punkt 2!
Trin 4. Opretter DAO med afstemning
DesvĂŠrre er der i RIDE-sproget endnu ikke mulighed for at arbejde med samlinger (dictionaries of dictionaries, iterators, reducers osv.). Men for alle operationer med flade samlinger key-value kan vi designe et system til at arbejde med strenge, svarende til nĂžglerne og deres dekodning.
Det er meget nemt at konkatere strenge, og strenge kan deles efter indekser.
Lad os som et testeksempel samle og analysere en streng og se, hvordan det pÄvirker resultatet af transaktionen.
Vi stoppede ved, at Alice ikke kunne underskrive Transfer-transaktionen, da denne mulighed var blokeret i @verifier for denne type transaktioner.
Lad os Þve os lidt med strenge, og sÄ giver vi lov til det.
RIDE Strings
Transaktionen er igen mulig, vi kan arbejde med strenge.

ïżŒ
SĂ„ alt i alt har vi det nĂždvendige for at skrive kompleks logik DAO dApp.
Data Transaktioner
Data Transaktioner:
âDen maksimale stĂžrrelse for en nĂžgle er 100 tegn, og en nĂžgle kan indeholde vilkĂ„rlige Unicode-tegn, herunder mellemrum og andre ikke-udskrivelige symboler. StrengvĂŠrdier har en grĂŠnse pĂ„ 32.768 bytes, og det maksimale antal mulige poster i data-transaktionen er 100. Samlet set er den maksimale stĂžrrelse af en data-transaktion cirka 140kbâââtil reference, nĂŠsten prĂŠcis lĂŠngden af Shakespeares skuespil âRomeo og Julieâ.â
Opretter DAO med fĂžlgende betingelser:
For at en startup kan fĂ„ finansiering ved at kalde getFunds() er der brug for stĂžtte fra mindst 2 deltagere â DAO-investorer. Udskriv Der kan hĂŠves prĂŠcist det belĂžb, som samlet er angivet til afstemning ejerne af DAO.
Lad os lave 3 typer nĂžgler og tilfĂžje logik til at arbejde med saldi i 2 nye funktioner vote og getFunds:
xxâŠxx_ia = investorer, tilgĂŠngelig saldo (vote, deposit, withdrawal)
xxâŠxx_sv = startups, antal stemmer (vote, getFunds)
xxâŠxx_sf = startups, antal stemmer (vote, getFunds)
xxâŠxx = offentlig adresse (35 tegn)
BemÊrk, at vi i Vote skal opdatere flere felter pÄ én gang:
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),WriteSet giver os mulighed for at lave flere registreringer inden for én invokeScript transaktion.
SÄdan ser det ud i key-value lagringssystemet DAO dApp, efter at Bob og Cooper har indskudt ia-indskud:

Indskudsfunktionen er blevet let ĂŠndret:

Nu kommer det vigtigste Ăžjeblik i DAO's aktiviteter â afstemning om projekter til finansiering.
Bob stemmer for projektet Neli med 500000 wavelets:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
I datalageret ser vi alle nĂždvendige optegnelser for adressen Neli:

Cooper har ogsÄ stemt for projektet Neli.

Lad os se pÄ koden for funktionen getFunds. Neli skal samle mindst 2 stemmer for at kunne trÊkke midler ud af DAO.

Neli planlĂŠgger at trĂŠkke halvdelen af det betroede belĂžb:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))
Hun lykkes med det, hvilket betyder, at DAO fungerer!
Vi har gennemgÄet processen med at oprette en DAO pÄ sprog RIDE4DAPPS.
I de nĂŠste dele vil vi dykke nĂŠrmere ned i refaktorering af koden og testcases.
Den komplette version af koden findes i
# 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
}
}
Kilde: habr.com
