
Hei!
Đ del, har vi undersĂžkt i detalj hvordan du oppretter og arbeider med en dApp (desentralisert applikasjon) i .
La oss nÄ teste det demonterte litt .
Trinn 3. Testing av dApp-kontoen

Hvilke problemer skynder seg umiddelbart til stemmene med Alice Dapp Regnskap?
For det fĂžrste:
Boob og Cooper kan ved et uhell sende penger til en dApp-adresse ved hjelp av en normal overfÞre transaksjoner og dermed ikke fÄ tilgang til dem tilbake.Dernest:
Vi begrenser ikke pÄ noen mÄte Alice fra Ä ta ut penger uten samtykke fra Boob og/eller Cooper. Siden, vÊr oppmerksom pÄ Ä bekrefte, vil alle transaksjoner fra Alice bli utfÞrt.
La oss fikse 2 ved Ă„ utestenge Alice overfĂžre transaksjoner. Distribuer det korrigerte skriptet:

ïżŒ
Vi prÞver Ä ta ut mynter med dApp Alice og signaturen hennes. Vi fÄr en feilmelding:

PrĂžver Ă„ trekke ut via uttak:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))Manuset fungerer og vi fant ut det andre punktet!
Trinn 4. Lag en DAO med stemmegivning
Dessverre gir RIDE-sprÄket ennÄ ikke muligheten til Ä jobbe med samlinger (ordbÞker, ordbÞker, iteratorer, reduseringer, etc.). Dog for eventuelle operasjoner pÄ flate samlinger nÞkkelverdi vi kan designe et system for arbeid med strenger, henholdsvis med nÞkler og deres dekryptering.
Strenger er veldig enkle Ă„ sette sammen, strenger kan skilles med indekser.
La oss samle og analysere strengen som et testtilfelle og sjekke hvordan dette vil pÄvirke resultatet av transaksjonen.
Vi bestemte oss for at Alice ikke kunne signere overfĂžringstransaksjonen, siden denne muligheten ble blokkert i @verifier for denne typen transaksjoner.
La oss Þve med strenger og sÄ lÞse dette.
RIDE strenger
Transaksjonen er mulig igjen, vi vet hvordan vi jobber med strenger.

ïżŒ
Totalt sett har vi alt du trenger for Ă„ skrive kompleks logikk DAO dApp.
Datatransaksjoner
Datatransaksjoner:
"Maksimal stĂžrrelse for en nĂžkkel er 100 tegn, og en nĂžkkel kan inneholde vilkĂ„rlige Unicode-kodepunkter inkludert mellomrom og andre ikke-utskrivbare symboler. Strengeverdier har en grense pĂ„ 32,768 100 byte og maksimalt antall mulige oppfĂžringer i datatransaksjoner er 140. Totalt sett er den maksimale stĂžrrelsen pĂ„ en datatransaksjon rundt XNUMX kb â for referanse, nesten nĂžyaktig lengden pĂ„ Shakespeares skuespill 'Romeo and Juliet' '."
Vi oppretter en DAO med fĂžlgende betingelser:
For at en startup skal fÄ finansiering ved Ä ringe getFunds() stÞtte fra minst 2 deltakere - DAO-investorer kreves. Ta ut det vil vÊre mulig nÞyaktig sÄ mye som summen angitt pÄ stemmegivning DAO-eiere.
La oss lage 3 typer nĂžkler og legge til logikk for arbeid med saldoer i 2 nye funksjoner vote and getFunds:
xxâŠxx_ia = investorer, tilgjengelig saldo (stemme, innskudd, uttak)
xxâŠxx_sv = startups, antall stemmer (stemme, getFunds)
xxâŠxx_sf = startups, antall stemmer (stemme, getFunds)
xxâŠxx = offentlig adresse (35 tegn)
Merknad i Vote vi trengte Ă„ oppdatere flere felt samtidig:
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),WriteSet lar oss lage flere poster samtidig i én invokeScript transaksjoner.
Slik ser det ut i nÞkkelverdilageret til DAO dApp etter at Bob og Cooper fylte pÄ ia- innskudd:

Innskuddsfunksjonen vÄr har endret seg litt:

NĂ„ kommer det viktigste Ăžyeblikket i DAOs aktiviteter - stemme for prosjekter for finansiering.
Bob stemmer for Neli-prosjektet pÄ 500000 XNUMX 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 oppfĂžringer for Neli-adressen:

Cooper stemte ogsÄ for Neli-prosjektet.

La oss ta en titt pÄ funksjonskoden getFunds. Neli mÄ samle minst 2 stemmer for Ä kunne ta ut midler fra DAO.

Neli kommer til Ă„ ta ut halvparten av belĂžpet som er betrodd henne:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))
Hun lykkes, det vil si at DAO fungerer!
Vi gjennomgikk prosessen med Ä lage en DAO pÄ sprÄket RIDE4DAPPS.
I de fÞlgende delene skal vi se nÊrmere pÄ koderefaktorering og casetesting.
Full kode inn
# 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: www.habr.com
