
Hej alla!
Рdel tittade vi i detalj pÄ hur man skapar och arbetar med dApp (decentraliserad applikation) i .
LÄt oss testa den demonterade lite nu .
Steg 3. Testa dApp-kontot

Vilka problem drabbar dig omedelbart med Alice? Dapp Konto?
För det första:
Boob och Cooper kan av misstag skicka pengar till dApp-adressen med vanliga överföring transaktioner och kommer dÀrför inte att kunna komma Ät dem tillbaka.För det andra:
Vi hindrar inte Alice pÄ nÄgot sÀtt frÄn att ta ut pengar utan godkÀnnande av Boob och/eller Cooper. Eftersom, var uppmÀrksam pÄ att verifiera, kommer alla transaktioner frÄn Alice att utföras.
LÄt oss fixa 2:an genom att förbjuda Alice överföring transaktioner. LÄt oss distribuera det korrigerade skriptet:

ïżŒ
Vi försöker ta ut mynt frÄn dApp Alice och hennes signatur. Vi fÄr ett felmeddelande:

LÄt oss försöka dra tillbaka via dra ut:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))Manuset fungerar och vi kom pÄ den andra punkten!
Steg 4. Skapa en DAO med röstning
TyvÀrr ger RIDE-sprÄket Ànnu inte möjligheten att arbeta med samlingar (ordboksordböcker, iteratorer, reducerare, etc.). Dock för alla operationer med platta samlingar nyckelvÀrde vi kan designa ett system för att arbeta med strÀngar, i enlighet dÀrmed med nycklar och deras dekryptering.
StrÀngar Àr mycket lÀtta att sammanfoga; strÀngar kan separeras med index.
LÄt oss samla och analysera en strÀng som ett testexempel och kontrollera hur detta pÄverkar resultatet av transaktionen.
Vi bestÀmde oss för att Alice inte kunde underteckna överföringstransaktionen, eftersom denna möjlighet var blockerad i @verifier för denna typ av transaktion.
LÄt oss öva med strÀngar och sedan lösa detta.
RIDE Strings
Transaktionen Àr möjlig igen, vi vet hur man arbetar med strÀngar.

ïżŒ
Totalt har vi allt som behövs för att skriva komplex logik DAO dApp.
Datatransaktioner
Datatransaktioner:
"Den maximala storleken för en nyckel Àr 100 tecken, och en nyckel kan innehÄlla godtyckliga Unicode-kodpunkter inklusive mellanslag och andra icke-utskrivbara symboler. StrÀngvÀrden har en grÀns pÄ 32,768 100 byte och det maximala antalet möjliga poster i datatransaktionen Àr 140. Totalt sett Àr den maximala storleken pÄ en datatransaktion cirka XNUMX kb - för referens, nÀstan exakt lÀngden pÄ Shakespeares pjÀs 'Romeo och Julia' '.
Vi skapar en DAO med följande villkor:
För att en startup ska fÄ finansiering genom att ringa getFunds() stöd frÄn minst 2 deltagare - DAO-investerare - krÀvs. dra tillbaka det kommer att vara möjligt exakt sÄ mycket som summan som anges pÄ röstning DAO-Àgare.
LÄt oss skapa 3 typer av nycklar och lÀgga till logik för att arbeta med saldon i 2 nya funktioner rösta och getFunds:
xxâŠxx_ia = investerare, tillgĂ€ngligt saldo (rösta, insĂ€ttning, uttag)
xxâŠxx_sv = startups, antal röster (rösta, getFunds)
xxâŠxx_sf = startups, antal röster (rösta, getFunds)
xxâŠxx = offentlig adress (35 tecken)
Observera att vi i Vote behövde uppdatera flera fÀlt samtidigt:
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),WriteSet tillÄter oss att göra flera poster samtidigt inom en invokeScript transaktioner.
SÄ hÀr ser det ut i nyckel-vÀrde-lagringen av DAO dApp, efter att Bob och Cooper fyllt pÄ ia-insÀttningar:

VÄr insÀttningsfunktion har Àndrats nÄgot:

Nu kommer det viktigaste ögonblicket i DAO:s verksamhet - rösta för projekt som ska finansieras.
Bob röstar pÄ Nelis 500000 XNUMX wavelets-projekt:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
I datalagret ser vi alla nödvÀndiga poster för Nelis adress:

Cooper röstade ocksÄ pÄ Neli-projektet.

LÄt oss ta en titt pÄ funktionskoden getFunds. Neli mÄste samla minst 2 röster för att kunna ta ut pengar frÄn DAO.

Neli kommer att ta ut hÀlften av det belopp som hon anförtrotts:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))
Hon lyckas, det vill sÀga DAO fungerar!
Vi tittade pÄ processen att skapa en DAO pÄ sprÄket RIDE4DAPPS.
I de följande delarna kommer vi att titta nÀrmare pÄ kodrefaktorering och falltestning.
Den fullstÀndiga versionen av 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
}
}
KĂ€lla: will.com
