
Zdravo svima!
V dio detaljno smo razmotrili kako kreirati i raditi s dApp (decentraliziranom aplikacijom) u .
Sada ćemo malo testirati razrađeni .
Faza 3. Testiranje dApp računa

Koje se probleme odmah uočava kod Alice dApp Račun?
Prvo:
Boob i Cooper mogu slučajno poslati sredstva na adresu dApp putem obične prenos transakcije i tako neće moći ponovno pristupiti njima.Drugo:
Mi nikako ne ograničavamo Alice u isplati sredstava bez odobrenja od Boob ili(ili) Coopera. Kao što, obratite pažnju na verifikaciju, sve transakcije od Alice će se izvršavati.
Ispravimo drugu, zabranjujući Alice prenos transakcije. Deploy-amo ispravljeni skript:


Pokušavamo povući novčiće s dApp Alice i njenim potpisom. Dobivamo grešku:

Pokušavamo povući putem withdraw:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))Skript radi i s drugim točkom smo se razjasnili!
Faza 4. Kreiramo DAO s glasovanjem
Nažalost, u jeziku RIDE trenutno nije predviđena mogućnost rada s kolekcijama (riječnici-riječnika, iteratori, reduktori itd.). Međutim, za bilo koje operacije s ravnim kolekcijama key-value možemo projektirati sustav rada sa stringovima, prema tome s ključevima i njihovim dekodiranjem.
Stringove je vrlo lako spojiti, stringove možemo dijeliti prema indeksima.
Pokažimo primjer kako ćemo sastaviti i razložiti string i provjeriti kako to utječe na ishod transakcije.
Stali smo na tome da Alice nije mogla potpisati Transfer transakciju, jer je ta mogućnost bila blokirana u @verifier za tu vrstu transakcija.
Pokažimo se sa stringovima i zatim ćemo to odobriti.
RIDE Stringovi
Transakcija je ponovno moguća, možemo raditi sa stringovima.


Dakle, imamo sve što nam je potrebno za pisanje složene logike DAO dApp.
Podatkovne transakcije
Podatkovne transakcije:
“Maksimalna veličina za ključ je 100 znakova, a ključ može sadržavati proizvoljne Unicode kodne točke uključujući razmake i druge nevidljive simbole. String vrijednosti imaju limit od 32,768 bajta, a maksimalni broj mogućih unosa u podatkovnoj transakciji je 100. Ukupna maksimalna veličina podatkovne transakcije iznosi oko 140kb — za referencu, gotovo točno dužina Šekspirove drame ‘Romeo i Julija’.”
Kreiramo DAO s sljedećim uvjetima:
Da bi startup dobio financijska sredstva, pozivajući getFunds() potrebna je podrška najmanje 2 sudionika — investitora DAO. Povući može se povući točno onoliko koliko je ukupno navedeno na glasovanju власници DAO.
Хајде да направимо 3 типа кључева и додамо логичке операције за управљање балансима у две нове функције vote и getFunds:
xx…xx_ia = инвеститори, доступан баланс (vote, deposit, withdrawal)
xx…xx_sv = стартупи, број гласова (vote, getFunds)
xx…xx_sf = стартупи, број гласова (vote, getFunds)
xx…xx = јавна адреса (35 знакова)
Обратите пажњу да у Vote морамо обновити неколико поља:
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),WriteSet нам омогућава да направимо више записа у оквиру једне invokeScript транзакције.
Овако изгледа у key-value складишту DAO dApp, након што су Bob и Cooper допунили ia-депозити:

Функција депозита је благом променила:

Сада долази најважнији тренутак у деловању DAO — гласање за пројекте које треба финансирати.
Bob гласа за пројекат Neli са 500000 wavelets:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
У складишту података видимо све потребне записа за адресу Neli:

Купер је такође гласао за пројекат Neli.

Погледајмо код функције getFunds. Neli мора сакупити најмање 2 гласа да би могла повући средства из DAO.

Neli планира да повуче половину износа који јој је поверен:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))
Успева, што значи да DAO функционише!
Размотрили смо процес стварања DAO на језику RIDE4DAPPS.
У следећим деловима ћемо детаљније размотрити рефакторинг кода и тестирање случајева.
Пуна верзија кода у
# 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: habr.com
