์๋ ํ์ญ๋๊น!
ะ
์ด์ ๋ถํด๋ ๊ฒ์ ์กฐ๊ธ ํ
์คํธํด ๋ณด๊ฒ ์ต๋๋ค.
3๋จ๊ณ. dApp ๊ณ์ ํ ์คํธ
Alice์ ๊ด๋ จํ์ฌ ์ด๋ค ๋ฌธ์ ๊ฐ ์ฆ์ ๋ฐ์ํฉ๋๊น? dApp ๊ณ์ ?
์ฒซ ๋ฒ์งธ :
Boob๊ณผ Cooper๋ ์ค์๋ก ์ผ๋ฐ ๊ณ์ ์ ์ฌ์ฉํ์ฌ dApp ์ฃผ์๋ก ์๊ธ์ ๋ณด๋ผ ์ ์์ต๋๋ค. ์ด์ ๊ฑฐ๋์ ๋ค์ ์ก์ธ์คํ ์ ์๊ฒ ๋ฉ๋๋ค.๋์งธ :
์ฐ๋ฆฌ๋ Boob ๋ฐ/๋๋ Cooper์ ์น์ธ ์์ด Alice๊ฐ ์๊ธ์ ์ธ์ถํ๋ ๊ฒ์ ์ด๋ค ์์ผ๋ก๋ ์ ํํ์ง ์์ต๋๋ค. ๊ฒ์ฆ์ ์ฃผ์ํ์๊ธฐ ๋ฐ๋๋๋ค. Alice์ ๋ชจ๋ ๊ฑฐ๋๊ฐ ์คํ๋ ๊ฒ์ ๋๋ค.
Alice๋ฅผ ๊ธ์งํ์ฌ ๋ ๋ฒ์งธ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ ์ด์ ์
๋ฌด. ์์ ๋ ์คํฌ๋ฆฝํธ๋ฅผ ๋ฐฐํฌํด ๋ณด๊ฒ ์ต๋๋ค.
๏ฟผ
์ฐ๋ฆฌ๋ dApp Alice์ ๊ทธ๋
์ ์๋ช
์์ ์ฝ์ธ์ ์ถ๊ธํ๋ ค๊ณ ํฉ๋๋ค. ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
์ฒ ํ๋ฅผ ํตํด ์ฒ ํ๋ฅผ ์๋ํด ๋ณด๊ฒ ์ต๋๋ค.
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))
์คํฌ๋ฆฝํธ๊ฐ ์๋ํ๊ณ ๋ ๋ฒ์งธ ์์ ์ ์์๋์ต๋๋ค!
4๋จ๊ณ. ํฌํ๋ฅผ ํตํด DAO ์์ฑ
๋ถํํ๊ฒ๋ RIDE ์ธ์ด๋ ์์ง ์ปฌ๋ ์ (์ฌ์ ์ฌ์ , ๋ฐ๋ณต์, ๋ฆฌ๋์ ๋ฑ) ์์ ๊ธฐ๋ฅ์ ์ ๊ณตํ์ง ์์ต๋๋ค. ๊ทธ๋ฌ๋ ํ๋ซ ์ปฌ๋ ์ ์ ์ฌ์ฉํ๋ ๋ชจ๋ ์์ ์ โโ๊ฒฝ์ฐ ํต์ฌ ๊ฐ์น ์ฐ๋ฆฌ๋ ํค์ ์ํธ ํด๋ ์ ๋ฐ๋ผ ๋ฌธ์์ด ์์ ์ ์ํ ์์คํ ์ ์ค๊ณํ ์ ์์ต๋๋ค.
๋ฌธ์์ด์ ์ฐ๊ฒฐํ๊ธฐ๊ฐ ๋งค์ฐ ์ฝ์ต๋๋ค. ๋ฌธ์์ด์ ์ธ๋ฑ์ค๋ก ๊ตฌ๋ถํ ์ ์์ต๋๋ค.
ํ
์คํธ ์์๋ก ๋ฌธ์์ด์ ์์งํ๊ณ ๊ตฌ๋ฌธ ๋ถ์ํ์ฌ ์ด๊ฒ์ด ํธ๋์ญ์
๊ฒฐ๊ณผ์ ์ด๋ค ์ํฅ์ ๋ฏธ์น๋์ง ํ์ธํด ๋ณด๊ฒ ์ต๋๋ค.
์ฐ๋ฆฌ๋ ์ด๋ฌํ ์ ํ์ ๊ฑฐ๋์ ๋ํด @verifier์์ ์ด ๊ธฐํ๊ฐ ์ฐจ๋จ๋์๊ธฐ ๋๋ฌธ์ Alice๊ฐ ์ด์ฒด ๊ฑฐ๋์ ์๋ช
ํ ์ ์๋ค๋ ์ฌ์ค์ ํฉ์ํ์ต๋๋ค.
๋ฌธ์์ด๋ก ์ฐ์ตํ ํ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด ๋ณด๊ฒ ์ต๋๋ค.
๋ผ์ด๋ ์คํธ๋ง
๊ฑฐ๋๊ฐ ๋ค์ ๊ฐ๋ฅํฉ๋๋ค. ์ฐ๋ฆฌ๋ ๋ฌธ์์ด ์์
๋ฐฉ๋ฒ์ ์๊ณ ์์ต๋๋ค.
๏ฟผ
์ ์ฒด์ ์ผ๋ก ์ฐ๋ฆฌ๋ ๋ณต์กํ ๋
ผ๋ฆฌ๋ฅผ ์์ฑํ๋ ๋ฐ ํ์ํ ๋ชจ๋ ๊ฒ์ ๊ฐ์ถ๊ณ ์์ต๋๋ค. DAO ๋์ฑ.
๋ฐ์ดํฐ ๊ฑฐ๋
๋ฐ์ดํฐ ๊ฑฐ๋:
โํค์ ์ต๋ ํฌ๊ธฐ๋ 100์์ด๋ฉฐ ํค์๋ ๊ณต๋ฐฑ ๋ฐ ๊ธฐํ ์ธ์ํ ์ ์๋ ๊ธฐํธ๋ฅผ ํฌํจํ์ฌ ์์์ ์ ๋์ฝ๋ ์ฝ๋ ํฌ์ธํธ๊ฐ ํฌํจ๋ ์ ์์ต๋๋ค. ๋ฌธ์์ด ๊ฐ์ 32,768๋ฐ์ดํธ๋ก ์ ํ๋๋ฉฐ ๋ฐ์ดํฐ ํธ๋์ญ์
์ ๊ฐ๋ฅํ ์ต๋ ํญ๋ชฉ ์๋ 100๊ฐ์
๋๋ค. ์ ์ฒด์ ์ผ๋ก ๋ฐ์ดํฐ ํธ๋์ญ์
์ ์ต๋ ํฌ๊ธฐ๋ ์ฝ 140kb์
๋๋ค. ์ฐธ๊ณ ๋ก ์
ฐ์ต์คํผ์ด์ ํฌ๊ณก '๋ก๋ฏธ์ค์ ์ค๋ฆฌ์ฃ'์ ๊ธธ์ด์ ๊ฑฐ์ ์ ํํ ๊ฐ์ต๋๋ค. '.โ
์ฐ๋ฆฌ๋ ๋ค์ ์กฐ๊ฑด์ผ๋ก DAO๋ฅผ ์์ฑํฉ๋๋ค.
์คํํธ์
์ด ์ ํํด์ ์๊ธ์ ๋ฐ๊ธฐ ์ํด์๋ getFunds() ์ต์ 2๋ช
์ ์ฐธ๊ฐ์(DAO ํฌ์์)์ ์ง์์ด ํ์ํฉ๋๋ค. ์ฒ ์ ์ ํ์๋ ์ด ๊ธ์ก๋งํผ ์ ํํ๊ฒ ๊ฐ๋ฅํฉ๋๋ค. ํฌํ DAO ์์ ์.
3๊ฐ์ง ์ ํ์ ํค๋ฅผ ๋ง๋ค๊ณ 2๊ฐ์ ์๋ก์ด ํจ์ vote ๋ฐ getFunds์์ ์์ก ์์ ์ ์ํ ๋ก์ง์ ์ถ๊ฐํด ๋ณด๊ฒ ์ต๋๋ค.
xxโฆxx_ia = ํฌ์์, ์ฌ์ฉ ๊ฐ๋ฅ ์์ก (ํฌํ, ์ ๊ธ, ์ถ๊ธ)
xxโฆxx_sv = ์คํํธ์ , ํฌํ์ (ํฌํ, getFunds)
xxโฆxx_sf = ์คํํธ์ , ํฌํ์ (ํฌํ, getFunds)
xxโฆxx = ๊ณต๊ฐ ์ฃผ์(35์)
Vote์์๋ ์ฌ๋ฌ ํ๋๋ฅผ ํ ๋ฒ์ ์ ๋ฐ์ดํธํด์ผ ํ์ต๋๋ค.
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 ํ๋ก์ ํธ์๋ ํฌํํ์ต๋๋ค.
ํจ์์ฝ๋๋ฅผ ์ดํด๋ณด์ getFunds. Neli๋ DAO์์ ์๊ธ์ ์ธ์ถํ๋ ค๋ฉด ์ต์ 2ํ๋ฅผ ๋ชจ์์ผ ํฉ๋๋ค.
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
}
}
์ถ์ฒ : habr.com