Hej alle!
В
Lad os teste den adskilte lidt nu
Trin 3. Test af dApp-kontoen
Hvilke problemer springer dig straks i øjnene med Alice? DAI Konto?
For det første:
Boob og Cooper kan ved et uheld sende penge til dApp-adressen ved hjælp af almindelig overførsel transaktioner og dermed ikke vil kunne få adgang til dem tilbage.For det andet:
Vi begrænser på ingen måde Alice i at hæve penge uden Boobs og/eller Coopers godkendelse. Da, vær opmærksom på at verificere, vil alle transaktioner fra Alice blive udført.
Lad os rette 2. ved at forbyde Alice overførsel transaktioner. Lad os implementere det rettede script:

Vi forsøger at trække mønter tilbage fra dApp Alice og hendes signatur. Vi får en fejl:
Lad os prøve at trække tilbage via tilbagetrækning:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))
Scriptet virker, og vi fandt ud af det 2. punkt!
Trin 4. Opret en DAO med afstemning
Desværre giver RIDE-sproget endnu ikke mulighed for at arbejde med samlinger (ordbogsordbøger, iteratorer, reduktionsmidler osv.). Dog til enhver operation med flade samlinger nøgleværdi vi kan designe et system til at arbejde med strenge, i overensstemmelse hermed med nøgler og deres dekryptering.
Strenge er meget nemme at sammenkæde; strenge kan adskilles af indekser.
Lad os samle og analysere en streng som et testeksempel og kontrollere, hvordan dette påvirker resultatet af transaktionen.
Vi slog os fast på det faktum, at Alice ikke kunne underskrive overførselstransaktionen, da denne mulighed var blokeret i @verifier for denne type transaktion.
Lad os øve os med strenge og så løse dette.
RIDE Strings
Transaktionen er mulig igen, vi ved, hvordan man arbejder med strenge.

I alt har vi alt det nødvendige for at skrive kompleks logik DAO dApp.
Datatransaktioner
Datatransaktioner:
"Den maksimale størrelse for en nøgle er 100 tegn, og en nøgle kan indeholde vilkårlige Unicode-kodepunkter inklusive mellemrum og andre ikke-udskrivbare symboler. Strengværdier har en grænse på 32,768 bytes, og det maksimale antal mulige indtastninger i datatransaktionen er 100. Samlet set er den maksimale størrelse af en datatransaktion omkring 140 kb - til reference, næsten nøjagtig længden af Shakespeares skuespil 'Romeo and Juliet' '."
Vi opretter en DAO med følgende betingelser:
For at en startup kan modtage finansiering ved at ringe getFunds() støtte fra mindst 2 deltagere - DAO-investorer - er påkrævet. trække det vil være muligt nøjagtigt så meget som totalen angivet på afstemning DAO ejere.
Lad os lave 3 typer nøgler og tilføje logik til at arbejde med saldi i 2 nye funktioner vote and getFunds:
xx…xx_ia = investorer, disponibel saldo (stemme, indskud, udbetaling)
xx…xx_sv = startups, antal stemmer (stem, getFunds)
xx…xx_sf = startups, antal stemmer (stem, getFunds)
xx…xx = offentlig adresse (35 tegn)
Bemærk venligst, at i afstemningen var vi nødt til at opdatere flere felter på én gang:
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),
WriteSet giver os mulighed for at lave flere poster på én gang inden for én invokeScript transaktioner.
Sådan ser det ud i nøgleværdilageret i DAO dApp, efter at Bob og Cooper genopfyldte ia-indskud:
Vores indbetalingsfunktion er ændret lidt:
Nu kommer det vigtigste øjeblik i DAO's aktiviteter - stemme for projekter, der skal finansieres.
Bob stemmer på Nelis 500000 wavelets-projekt:
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 de nødvendige indtastninger til Nelis adresse:
Cooper stemte også for Neli-projektet.
Lad os tage et kig på funktionskoden getFunds. Neli skal indsamle minimum 2 stemmer for at kunne hæve midler fra DAO.
Neli vil hæve halvdelen af det beløb, hun har fået betroet:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))
Hun lykkes, det vil sige, DAO virker!
Vi så på processen med at skabe en DAO på sproget RIDE4DAPPS.
I de følgende dele vil vi se nærmere på kode refactoring og case test.
Fuld version af koden 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: www.habr.com