大家好!
В
現在我們拆開來測試一下
第 3 階段. 測試 dApp 帳戶
與愛麗絲在一起時,您立即會遇到什麼問題? DAPP 帳戶?
首先:
Boob 和 Cooper 可能會意外地使用常規方式將資金發送到 dApp 地址 轉讓 交易,因此將無法存取它們。其次:
未經 Boob 和/或 Cooper 批准,我們不會以任何方式限制 Alice 提取資金。 因為,注意驗證,所有來自Alice的交易都會被執行。
讓我們透過禁止 Alice 來解決第二個問題 轉讓 交易。 讓我們部署更正後的腳本:

我們正在嘗試從 dApp Alice 和她的簽名中提取代幣。 我們得到一個錯誤:
讓我們嘗試透過withdraw來提現:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))
腳本成功了,我們找到了第二點!
第 4 階段:創建一個有投票功能的 DAO
不幸的是,RIDE 語言尚未提供使用集合(字典字典、迭代器、化簡器等)的能力。 但是,對於任何使用平面集合的操作 核心價值 我們可以設計一個處理字串的系統,並相應地使用金鑰及其解密。
字串非常容易連接;字串可以透過索引分隔。
讓我們收集並解析一個字串作為測試範例,並檢查這如何影響交易的結果。
我們確定了 Alice 無法簽署 Transfer 交易的事實,因為這種能力在此類交易的 @verifier 中被阻止。
讓我們用字串練習一下,然後解決這個問題。
騎行弦
交易再次成為可能,我們知道如何使用字串。

總的來說,我們擁有編寫複雜邏輯所需的一切 DAO dApp.
數據交易
數據交易:
「金鑰的最大大小為 100 個字符,且金鑰可以包含任意 Unicode 代碼點,包括空格和其他不可列印的符號。 字串值的限制為 32,768 字節,資料事務中可能的最大條目數為 100。總體而言,資料事務的最大大小約為 140kb — 作為參考,幾乎恰好是莎士比亞戲劇《羅密歐與茱麗葉》的長度' 。”
我們創建一個 DAO 並滿足以下條件:
為了讓新創公司透過致電獲得資金 獲取資金() 需要至少 2 位參與者(DAO 投資者)的支持。 撤 可能與上圖所示的總數完全相同 表決 DAO 所有者。
讓我們建立 3 種類型的鍵,並在 2 個新函數 vote 和 getFunds 中加入處理餘額的邏輯:
xx…xx_ia = 投資人、可用餘額 (投票、儲值、提現)
xx…xx_sv = 新創公司, 票數 (投票,獲取資金)
xx…xx_sf = 新創公司, 票數 (投票,獲取資金)
xx…xx = 公用位址(35 個字元)
請注意,在投票中我們需要一次更新多個欄位:
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),
WriteSet 允許我們在一個記錄中同時建立多個記錄 呼叫腳本 交易。
這就是 Bob 和 Cooper 補充後 DAO dApp 的鍵值儲存中的樣子 ia- 存款:
我們的存款功能略有變動:
現在到了 DAO 活動中最重要的時刻 - 投票 對於要融資的項目。
Bob 投票支持 Neli 的 500000 萬個小波項目:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
在資料儲存中,我們看到 Neli 位址的所有必要條目:
Cooper 也投票支持了 Neli 計畫。
我們來看看函數程式碼 獲取資金。 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
}
}
來源: www.habr.com