みなさん、こんにちは!
В
分解したものを少しテストしてみましょう
ステージ 3. dApp アカウントのテスト
アリスの場合、すぐにどんな問題が頭に浮かびますか? dApp アカウント?
まず:
ブーブとクーパーは、通常の方法を使用して誤って dApp アドレスに資金を送信する可能性があります。 転送 トランザクションが削除されるため、それらに再度アクセスすることはできません。第二に:
当社は、アリスがブーブおよび/またはクーパーの承認なしに資金を引き出すことをいかなる形でも制限しません。 アリスからのすべてのトランザクションが実行されるため、検証に注意してください。
アリスを禁止して2番目を修正しましょう 転送 取引。 修正したスクリプトをデプロイしてみましょう。

dApp アリスと彼女の署名からコインを出金しようとしています。 エラーが発生します:
引き出しを使って引き出しを試してみましょう:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))
スクリプトは機能し、2 番目のポイントがわかりました。
ステージ 4. 投票を含む DAO を作成する
残念ながら、RIDE 言語にはコレクション (辞書辞書、イテレータ、リデューサなど) を操作する機能がまだ提供されていません。 ただし、フラット コレクションを使用する操作の場合は、 Key-Value 文字列を操作し、それに応じてキーとその復号化を行うシステムを設計できます。
文字列の連結は非常に簡単で、文字列はインデックスで区切ることができます。
テスト例として文字列を収集して解析し、これがトランザクションの結果にどのような影響を与えるかを確認してみましょう。
このタイプのトランザクションではこの機能が @verifier でブロックされていたため、Alice が Transfer トランザクションに署名できないという事実に落ち着きました。
文字列で練習してからこの問題を解決しましょう。
ライドストリングス
トランザクションは再び可能になり、文字列の操作方法がわかりました。

合計すると、複雑なロジックを作成するために必要なものがすべて揃っています DAO dApp.
データトランザクション
データトランザクション:
「キーの最大サイズは 100 文字で、キーにはスペースやその他の印刷不可能な記号を含む任意の Unicode コード ポイントを含めることができます。 文字列値には 32,768 バイトの制限があり、データ トランザクションで可能なエントリの最大数は 100 です。全体として、データ トランザクションの最大サイズは約 140 kb です。参考までに、これはシェイクスピアの戯曲「ロミオとジュリエット」の長さとほぼ同じです。 「。」
次の条件で DAO を作成します。
スタートアップが電話で資金調達を受けるには getFunds() 少なくとも 2 人の参加者 (DAO 投資家) のサポートが必要です。 取り下げます に記載されている合計金額まで可能です。 投票 DAOの所有者。
3 種類のキーを作成し、2 つの新しい関数 vote と getFunds で残高を操作するためのロジックを追加しましょう。
xx…xx_ia = 投資家、利用可能残高 (投票、入金、出金)
xx…xx_sv = スタートアップ、投票数 (投票して資金を獲得)
xx…xx_sf = スタートアップ、投票数 (投票して資金を獲得)
xx…xx = パブリックアドレス (35 文字)
Vote では、複数のフィールドを一度に更新する必要があることに注意してください。
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),
WriteSet を使用すると、XNUMX つのレコード内で複数のレコードを同時に作成できます。 呼び出しスクリプト 取引。
これは、Bob と Cooper が補充された後の、DAO dApp のキーと値のストレージ内の様子です。 ia-預金:
入金機能が若干変更されました:
DAOの活動において最も重要な瞬間が来ました - 投票 資金提供を受けるプロジェクトのために。
ボブは Neli の 500000 ウェーブレット プロジェクトに投票します。
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
データ ストアには、Neli の住所に必要なすべてのエントリが表示されます。
クーパー氏も Neli プロジェクトに投票した。
関数コードを見てみましょう 資金を得る。 Neli が DAO から資金を引き出すには、少なくとも 2 票を集める必要があります。
ネリは、預けられた金額の半分を引き出すつもりです。
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
}
}
出所: habr.com