Sveiki visiem!
В
Tagad nedaudz pārbaudīsim izjaukto
3. posms. dApp konta pārbaude
Kādas problēmas jums uzreiz uznāk ar Alisi? dApp Konts?
Pirmkārt:
Būs un Kūpers var nejauši nosūtīt līdzekļus uz dApp adresi, izmantojot parasto pārsūtīt darījumiem un tādējādi nevarēs tiem piekļūt atpakaļ.Otrkārt:
Mēs nekādā veidā neierobežojam Alises iespēju izņemt līdzekļus bez Boob un/vai Kūpera piekrišanas. Tā kā, pievērsiet uzmanību pārbaudei, visi darījumi no Alises tiks izpildīti.
Labosim 2., aizliedzot Alisi pārsūtīt darījumiem. Izvietosim laboto skriptu:

Mēs cenšamies izņemt monētas no dApp Alises un viņas paraksta. Mēs saņemam kļūdu:
Mēģināsim izņemt, izmantojot izņemšanu:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))
Scenārijs strādā, un mēs izdomājām 2. punktu!
4. posms. Izveidojiet DAO ar balsošanu
Diemžēl RIDE valoda vēl nenodrošina iespēju strādāt ar kolekcijām (vārdnīcu vārdnīcām, iteratoriem, reducētājiem utt.). Tomēr jebkurai darbībai ar plakanām kolekcijām atslēgas vērtība varam izstrādāt sistēmu darbam ar virknēm, attiecīgi ar atslēgām un to atšifrēšanu.
Virknes ir ļoti viegli savienot; virknes var atdalīt ar indeksiem.
Apkoposim un parsēsim virkni kā testa piemēru un pārbaudīsim, kā tas ietekmē darījuma iznākumu.
Mēs samierinājāmies ar faktu, ka Alise nevarēja parakstīt pārsūtīšanas darījumu, jo šī iespēja tika bloķēta @verifier šāda veida darījumam.
Praktizēsimies ar stīgām un pēc tam atrisināsim to.
RIDE Stīgas
Darījums atkal ir iespējams, mēs protam strādāt ar stīgām.

Kopumā mums ir viss nepieciešamais sarežģītas loģikas rakstīšanai DAO dApp.
Datu transakcijas
Datu darījumi:
“Maksimālais atslēgas izmērs ir 100 rakstzīmes, un atslēgā var būt patvaļīgi unikoda koda punkti, tostarp atstarpes un citi nedrukājami simboli. Virkņu vērtību ierobežojums ir 32,768 100 baiti, un maksimālais iespējamo ierakstu skaits datu transakcijā ir 140. Kopumā maksimālais datu transakcijas lielums ir aptuveni XNUMX kb — atsaucei gandrīz precīzi Šekspīra lugas “Romeo un Džuljeta” garums. '.”
Mēs izveidojam DAO ar šādiem nosacījumiem:
Lai jaunuzņēmums saņemtu finansējumu, zvanot pa tālr getFunds () nepieciešams vismaz 2 dalībnieku - DAO investoru - atbalsts. Izeja tas būs iespējams tieši tik, cik kopā norādīts balsošana DAO īpašnieki.
Izgatavosim 3 veidu atslēgas un pievienosim loģiku darbam ar atlikumiem 2 jaunās funkcijās balsošana un saņemšana:
xx…xx_ia = investori, pieejamais atlikums (balsošana, depozīts, izņemšana)
xx…xx_sv = starta uzņēmumi, balsu skaits (balsot, saņemt līdzekļus)
xx…xx_sf = starta uzņēmumi, balsu skaits (balsot, saņemt līdzekļus)
xx…xx = publiskā adrese (35 rakstzīmes)
Lūdzu, ņemiet vērā, ka balsojumā mums bija jāatjaunina vairāki lauki vienlaikus:
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),
WriteSet ļauj mums vienā reizē veikt vairākus ierakstus invokeScript darījumiem.
Šādi tas izskatās DAO dApp atslēgu vērtību krātuvē pēc tam, kad Bobs un Kūpers ir papildinājuši ia- noguldījumi:
Mūsu depozīta funkcija ir nedaudz mainījusies:
Tagad ir pienācis vissvarīgākais brīdis DAO darbībā - balsojums finansējamiem projektiem.
Bobs balso par Nelijas 500000 XNUMX viļņu projektu:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
Datu krātuvē redzam visus nepieciešamos ierakstus Nelija adresei:
Kūpers arī balsoja par Neli projektu.
Apskatīsim funkcijas kodu saņemtFunds. Neli ir jāsavāc vismaz 2 balsis, lai varētu izņemt līdzekļus no DAO.
Neli gatavojas izņemt pusi no viņai uzticētās summas:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))
Viņai tas izdodas, tas ir, DAO strādā!
Mēs apskatījām DAO izveides procesu valodā RIDE4DAPPS.
Nākamajās daļās mēs sīkāk aplūkosim koda pārveidošanu un gadījumu testēšanu.
Pilna koda versija iekšā
# 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
}
}
Avots: www.habr.com