
Pozdrav svima!
В dijelu smo detaljno pogledali kako kreirati i raditi s dApp-om (decentralizirana aplikacija) u .
Hajde da sada malo testiramo rastavljenu .
Faza 3. Testiranje dApp naloga

Koji problemi vam odmah napadaju s Alisom? dApp Račun?
Prvo:
Boob i Cooper mogu slučajno poslati sredstva na dApp adresu koristeći regularnu transfer transakcije i stoga im neće moći pristupiti nazad.Drugo:
Ne ograničavamo Alice ni na koji način u povlačenju sredstava bez odobrenja Boob-a i/ili Coopera. Pošto, obratite pažnju na verifikaciju, sve transakcije od Alice će biti izvršene.
Popravimo 2. banovanjem Alice transfer transakcije. Hajde da primenimo ispravljenu skriptu:


Pokušavamo povući novčiće iz dApp Alice i njen potpis. Dobijamo grešku:

Pokušajmo se povući putem povlačenja:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))
Scenarij radi i shvatili smo 2. tačku!
Faza 4. Kreirajte DAO sa glasanjem
Nažalost, jezik RIDE još uvijek ne pruža mogućnost rada sa kolekcijama (rječnici, iteratori, reduktori, itd.). Međutim, za sve operacije sa ravnim kolekcijama ključ-vrijednost možemo dizajnirati sistem za rad sa stringovima, u skladu sa ključevima i njihovom dešifrovanjem.
Stringove je vrlo lako spojiti;
Hajde da prikupimo i raščlanimo string kao testni primer i proverimo kako to utiče na ishod transakcije.
Sredili smo se na činjenici da Alice nije mogla potpisati Transfer transakciju, jer je ova mogućnost blokirana u @verifikatoru za ovu vrstu transakcije.
Vježbajmo sa žicama i onda riješimo ovo.
RIDE Strings
Transakcija je opet moguća, znamo raditi sa stringovima.


Ukupno imamo sve što je potrebno za pisanje složene logike DAO dApp.
Transakcije podataka
Transakcije podataka:
„Maksimalna veličina ključa je 100 znakova, a ključ može sadržavati proizvoljne Unicode kodne tačke uključujući razmake i druge simbole koji se ne mogu ispisati. Vrijednosti nizova imaju ograničenje od 32,768 bajtova, a maksimalni broj mogućih unosa u transakciji podataka je 100. Sveukupno, maksimalna veličina transakcije podataka je oko 140 kb — za referencu, skoro tačno koliko traje Shakespeareova drama 'Romeo i Julija '.
Mi kreiramo DAO sa sledećim uslovima:
Kako bi startup dobio sredstva pozivom getFunds() potrebna je podrška najmanje 2 učesnika - DAO investitora. Povuci to će biti moguće tačno onoliko koliko je ukupno navedeno na glasanje DAO vlasnici.
Napravimo 3 vrste ključeva i dodajmo logiku za rad sa stanjem u 2 nove funkcije vote i getFunds:
xx…xx_ia = investitori, raspoloživi bilans (glasanje, depozit, povlačenje)
xx…xx_sv = startupi, broj glasova (glasajte, nabavite sredstva)
xx…xx_sf = startupi, broj glasova (glasajte, nabavite sredstva)
xx…xx = javna adresa (35 znakova)
Napominjemo da smo u Glasanju morali ažurirati nekoliko polja odjednom:
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),
WriteSet nam omogućava da napravimo nekoliko zapisa odjednom unutar jednog invokeScript transakcije.
Ovako to izgleda u skladištu ključ/vrijednost DAO dApp, nakon što su Bob i Cooper dopunili ia- depoziti:

Naša funkcija depozita je malo promijenjena:

Sada dolazi najvažniji trenutak u aktivnostima DAO-a - glasajte za projekte koji će se finansirati.
Bob glasa za Neliin projekat 500000 talasa:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))

U skladištu podataka vidimo sve potrebne unose za Nelinu adresu:

Cooper je takođe glasao za projekat Neli.

Pogledajmo kod funkcije getFunds. Neli mora prikupiti minimalno 2 glasa da bi mogla povući sredstva iz DAO-a.

Neli će podići polovinu iznosa koji joj je poveren:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))

Ona uspeva, odnosno DAO radi!
Pogledali smo proces stvaranja DAO-a na jeziku RIDE4DAPPS.
U sljedećim dijelovima ćemo detaljnije pogledati refaktoriranje koda i testiranje slučajeva.
Puna verzija koda u
# 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
}
}
izvor: www.habr.com
