์๋ ํ์ธ์! ์ด ๊ธฐ์ฌ์์๋ Waves ๋ ธ๋์์ ์ผ๋ฐ dApp์ ์์ฑํ๊ณ ์คํํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ ๋๋ฆฌ๊ฒ ์ต๋๋ค. ํ์ํ ๋๊ตฌ์ ๋ฐฉ๋ฒ, ๊ฐ๋ฐ ์ฌ๋ก๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
dApp๊ณผ ์ผ๋ฐ ์ ํ๋ฆฌ์ผ์ด์
์ ๊ฐ๋ฐ ๊ณํ์ ๊ฑฐ์ ๋์ผํฉ๋๋ค.
- ์ฐ๋ฆฌ๋ ์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค
- ์๋ํ๋ ํ ์คํธ ์์ฑ
- ์ ํ๋ฆฌ์ผ์ด์ ์คํ
- ํ ์คํธ
๋๊ตฌ
1. docker
๋
ธ๋์ Waves Explorer๋ฅผ ์คํํ๋ ค๋ฉด
๋ ธ๋๋ฅผ ์์ํ์ง ์์ผ๋ ค๋ฉด ์ด ๋จ๊ณ๋ฅผ ๊ฑด๋๋ธ ์ ์์ต๋๋ค. ๊ฒฐ๊ตญ ํ ์คํธ ๋ฐ ์คํ ๋คํธ์ํฌ๊ฐ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์์ฒด ๋ ธ๋๋ฅผ ๋ฐฐํฌํ์ง ์์ผ๋ฉด ํ ์คํธ ํ๋ก์ธ์ค๊ฐ ์ง์ฐ๋ ์ ์์ต๋๋ค.
- ํ ์คํธ ํ ํฐ์ด ์๋ ์ ๊ณ์ ์ด ์ง์์ ์ผ๋ก ํ์ํฉ๋๋ค. ํ ์คํธ ๋คํธ์ํฌ ์๋๊ผญ์ง๋ 10๋ถ๋ง๋ค 10๊ฐ์ WAVES๋ฅผ ์ ์กํฉ๋๋ค.
- ํ ์คํธ ๋คํธ์ํฌ์ ํ๊ท ๋ธ๋ก ์๊ฐ์ 1๋ถ์ด๊ณ , ๋ ธ๋์์๋ 15์ด์ ๋๋ค. ์ด๋ ๊ฑฐ๋์ ์ฌ๋ฌ ๋ฒ์ ํ์ธ์ด ํ์ํ ๋ ํนํ ๋๋๋ฌ์ง๋๋ค.
- ๊ณต๊ฐ ํ ์คํธ ๋ ธ๋์์๋ ๊ณต๊ฒฉ์ ์ธ ์บ์ฑ์ด ๊ฐ๋ฅํฉ๋๋ค.
- ๋ํ ์ ์ง๋ณด์๋ก ์ธํด ์ผ์์ ์ผ๋ก ์ด์ฉ์ด ๋ถ๊ฐ๋ฅํ ์๋ ์์ต๋๋ค.
์ด์ ๋ถํฐ๋ ์ฌ๋ฌ๋ถ์ด ์์ ์ ๋ ธ๋๋ก ์์ ํ๊ณ ์๋ค๊ณ ๊ฐ์ ํ๊ฒ ์ต๋๋ค.
2. ์ํ๋ณด๋ ๋ช ๋ น์ค ๋๊ตฌ
- ์ฌ๊ธฐ์์ ppa, homebrew ๋๋ exe๋ฅผ ์ฌ์ฉํ์ฌ Node.js๋ฅผ ๋ค์ด๋ก๋ํ๊ณ ์ค์นํ์ธ์.
https://nodejs.org/en/download/ . - ๊ธฐ์กด ๋ ธ๋์์ ํ ์คํธ๋ฅผ ์คํํ ์ ์๋ ๋๊ตฌ์ธ Surfboard๋ฅผ ์ค์นํฉ๋๋ค.
npm install -g @waves/surfboard
3. Visual Studio Code ํ๋ฌ๊ทธ์ธ
IDE ํฌ์ด ์๋๊ณ ํ
์คํธ ํธ์ง๊ธฐ๋ฅผ ์ ํธํ๋ ๊ฒฝ์ฐ ์ด ๋จ๊ณ๋ ์ ํ ์ฌํญ์
๋๋ค. ํ์ํ ๋ชจ๋ ๋๊ตฌ๋ ๋ช
๋ น์ค ์ ํธ๋ฆฌํฐ์
๋๋ค. vim์ ์ฌ์ฉํ๋ค๋ฉด ํ๋ฌ๊ทธ์ธ์ ์ฃผ์ํ์ธ์
Visual Studio Code๋ฅผ ๋ค์ด๋ก๋ํ๊ณ ์ค์นํฉ๋๋ค.
VS Code๋ฅผ ์ด๊ณ wave-ride ํ๋ฌ๊ทธ์ธ์ ์ค์นํฉ๋๋ค.
Waves Keeper ๋ธ๋ผ์ฐ์ ํ์ฅ:
์๋ฃ!
๋ ธ๋ ๋ฐ Waves Explorer ์์
1. ๋ ธ๋๋ฅผ ์์ํฉ๋๋ค.
docker run -d -p 6869:6869 wavesplatform/waves-private-node
๋
ธ๋๊ฐ REST API๋ฅผ ํตํด ์คํ๋๋์ง ํ์ธํ์ธ์.
๋
ธ๋์ฉ Swagger REST API
2. Waves Explorer ์ธ์คํด์ค๋ฅผ ์์ํฉ๋๋ค.
docker run -d -e API_NODE_URL=http://localhost:6869 -e NODE_LIST=http://localhost:6869 -p 3000:8080 wavesplatform/explorer
๋ธ๋ผ์ฐ์ ๋ฅผ ์ด๊ณ ๋ค์์ผ๋ก ์ด๋ํ์ญ์์ค.
Waves Explorer์ ๋ก์ปฌ ๋
ธ๋ ์ธ์คํด์ค๊ฐ ํ์๋ฉ๋๋ค.
RIDE ๊ตฌ์กฐ ๋ฐ ์ํ๋ณด๋ ๋๊ตฌ
๋น ๋๋ ํฐ๋ฆฌ๋ฅผ ๋ง๋ค๊ณ ๊ทธ ์์์ ๋ช ๋ น์ ์คํํ์ธ์.
surfboard init
์ด ๋ช ๋ น์ ํ๋ก์ ํธ ๊ตฌ์กฐ, "hello world" ์ ํ๋ฆฌ์ผ์ด์ ๋ฐ ํ ์คํธ๋ฅผ ์ฌ์ฉํ์ฌ ๋๋ ํฐ๋ฆฌ๋ฅผ ์ด๊ธฐํํฉ๋๋ค. VS Code๋ก ์ด ํด๋๋ฅผ ์ด๋ฉด ๋ค์์ด ํ์๋ฉ๋๋ค.
Surfboard.config.json
- ./ride/ ํด๋ ์๋์ ๋จ์ผ ํ์ผ wallet.ride(dApp ์ฝ๋๊ฐ ์๋ ๋๋ ํฐ๋ฆฌ)๊ฐ ์์ต๋๋ค. ๋ค์ ๋ธ๋ก์์๋ dApp์ ๊ฐ๋ตํ๊ฒ ๋ถ์ํ๊ฒ ์ต๋๋ค.
- ./test/ ํด๋ ์๋์ *.js ํ์ผ์ด ์์ต๋๋ค. ํ ์คํธ๋ ์ฌ๊ธฐ์ ์ ์ฅ๋ฉ๋๋ค.
- ./surfboard.config.json โ ํ ์คํธ ์คํ์ ์ํ ๊ตฌ์ฑ ํ์ผ์ ๋๋ค.
Envs๋ ์ค์ํ ์น์ ์ ๋๋ค. ๊ฐ ํ๊ฒฝ์ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌ์ฑ๋ฉ๋๋ค.
- dApp์ ์คํํ๋ ๋ฐ ์ฌ์ฉ๋ ๋ ธ๋์ REST API ์๋ํฌ์ธํธ์ ๋คํธ์ํฌ์ CHAIN_ID์ ๋๋ค.
- ํ ์คํธ ํ ํฐ์ ์์ค๊ฐ ๋ ํ ํฐ์ด ์๋ ๊ณ์ ์ ๋ํ ๋น๋ฐ ๋ฌธ๊ตฌ์ ๋๋ค.
๋ณด์๋ค์ํผ, Surfboard.config.json์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฌ๋ฌ ํ๊ฒฝ์ ์ง์ํฉ๋๋ค. ๊ธฐ๋ณธ๊ฐ์ ๋ก์ปฌ ํ๊ฒฝ์ ๋๋ค(defaultEnv ํค๋ ๋ณ๊ฒฝ ๊ฐ๋ฅํ ๋งค๊ฐ๋ณ์์ ๋๋ค).
์ง๊ฐ ๋ฐ๋ชจ ์ ํ๋ฆฌ์ผ์ด์
์ด ์น์ ์ RIDE ์ธ์ด์ ๋ํ ์ฐธ์กฐ๊ฐ ์๋๋๋ค. ๊ทธ๋ณด๋ค๋ ๋ธ๋ก์ฒด์ธ์์ ๋ฌด์จ ์ผ์ด ์ผ์ด๋๊ณ ์๋์ง ๋ ์ ์ดํดํ๊ธฐ ์ํด ๋ฐฐํฌํ๊ณ ํ ์คํธํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ดํด๋ณด์ธ์.
๊ฐ๋จํ Wallet ๋ฐ๋ชจ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ๋๊ตฌ๋ dApp ์ฃผ์๋ก ํ ํฐ์ ๋ณด๋ผ ์ ์์ต๋๋ค. WAVES๋ง ์ธ์ถํ ์ ์์ต๋๋ค. InvokeScriptTransaction์ ํตํด ๋ ๊ฐ์ง @Callable ํจ์๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
deposit()
WAVES์ ์ฒจ๋ถ๋ ๊ฒฐ์ ๊ฐ ํ์ํฉ๋๋ค.withdraw(amount: Int)
ํ ํฐ์ ๋ฐํํ๋
dApp ๋ผ์ดํ์ฌ์ดํด ์ ๋ฐ์ ๊ฑธ์ณ ๊ตฌ์กฐ(์ฃผ์ โ ๊ธ์ก)๊ฐ ์ ์ง๋ฉ๋๋ค.
๋์
๊ฒฐ๊ณผ ์ํ
์ฒ์์๋
๋น
์จ๋ฆฌ์ค๋ 5 WAVES๋ฅผ ์์นํฉ๋๋ค.
์จ๋ฆฌ์ค ์ฃผ์ โ 500000000
Bob์ 2 WAVES๋ฅผ ์
๊ธํ์ต๋๋ค.
์จ๋ฆฌ์ค ์ฃผ์ โ 500000000
๋ฐฅ ์ฃผ์ โ 200000000
Bob์ 7 WAVES๋ฅผ ์ธ์ถํฉ๋๋ค.
๊ฑฐ๋ถ๋จ!
์จ๋ฆฌ์ค๋ 4๊ฐ์ WAVES๋ฅผ ์ธ์ถํฉ๋๋ค.
์จ๋ฆฌ์ค ์ฃผ์ โ 100000000
๋ฐฅ ์ฃผ์ โ 200000000
์ํฉ์ ์์ ํ ์ดํดํ๋ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
# In this example multiple accounts can deposit their funds and safely take them back. No one can interfere with this.
# An inner state is maintained as mapping `address=>waves`.
{-# STDLIB_VERSION 3 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}
@Callable(i)
func deposit() = {
let pmt = extract(i.payment)
if (isDefined(pmt.assetId))
then throw("works with waves only")
else {
let currentKey = toBase58String(i.caller.bytes)
let currentAmount = match getInteger(this, currentKey) {
case a:Int => a
case _ => 0
}
let newAmount = currentAmount + pmt.amount
WriteSet([DataEntry(currentKey, newAmount)])
}
}
@Callable(i)
func withdraw(amount: Int) = {
let currentKey = toBase58String(i.caller.bytes)
let currentAmount = match getInteger(this, currentKey) {
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(currentKey, newAmount)]),
TransferSet([ScriptTransfer(i.caller, amount, unit)])
)
}
@Verifier(tx)
func verify() = false
์ํ ์ฝ๋๋ ๋ค์์์๋ ์ฐพ์ ์ ์์ต๋๋ค.
VSCode ํ๋ฌ๊ทธ์ธ์ ํ์ผ์ ํธ์งํ๋ ๋์ ์ง์์ ์ธ ์ปดํ์ผ์ ์ง์ํฉ๋๋ค. ๋ฐ๋ผ์ ๋ฌธ์ ํญ์์ ํญ์ ์ค๋ฅ๋ฅผ ๋ชจ๋ํฐ๋งํ ์ ์์ต๋๋ค.
ํ์ผ์ ์ปดํ์ผํ ๋ ๋ค๋ฅธ ํ
์คํธ ํธ์ง๊ธฐ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ๋ค์์ ์ฌ์ฉํ์ธ์.
surfboard compile ride/wallet.ride
๊ทธ๋ฌ๋ฉด ์ผ๋ จ์ base64 ์ปดํ์ผ๋ RIDE ์ฝ๋๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค.
'wallet.ride'์ ๋ํ ํ ์คํธ ์คํฌ๋ฆฝํธ
์ดํด ๋ณด์
- "์ด์ "์ MassTransferTransaction์ ํตํด ์ฌ๋ฌ ๊ณ์ ์ ์๊ธ์ ์กฐ๋ฌํ๊ณ ์คํฌ๋ฆฝํธ๋ฅผ ์ปดํ์ผํ์ฌ ๋ธ๋ก์ฒด์ธ์ ๋ฐฐํฌํฉ๋๋ค.
- "์๊ธ ๊ฐ๋ฅ"์ InvokeScriptTransaction์ ๋คํธ์ํฌ๋ก ์ ์กํ์ฌ ๋ ๊ณ์ ๊ฐ๊ฐ์ ๋ํด ์๊ธ() ๊ธฐ๋ฅ์ ํ์ฑํํฉ๋๋ค.
- ๋๊ตฌ๋ ๋ค๋ฅธ ์ฌ๋์ ํ ํฐ์ ํ์น ์ ์๋ค๋ โ์์น๋ ๊ฒ๋ณด๋ค ๋ ๋ง์ ๊ธ์ก์ ์ธ์ถํ ์ ์์ต๋๋คโ ํ ์คํธ์ ๋๋ค.
- โ์ ๊ธ ๊ฐ๋ฅโ์ ์ถ๊ธ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌ๋์๋์ง ํ์ธํฉ๋๋ค.
Surfboard์์ ํ ์คํธ๋ฅผ ์คํํ๊ณ Waves Explorer์์ ๊ฒฐ๊ณผ๋ฅผ ๋ถ์ํ์ธ์.
ํ ์คํธ๋ฅผ ์คํํ๋ ค๋ฉด ๋ค์์ ์คํํ์ธ์.
surfboard test
์ฌ๋ฌ ์คํฌ๋ฆฝํธ๊ฐ ์๋ ๊ฒฝ์ฐ(์: ๋ณ๋์ ๋ฐฐํฌ ์คํฌ๋ฆฝํธ๊ฐ ํ์ํจ) ๋ค์์ ์คํํ ์ ์์ต๋๋ค.
surfboard test my-scenario.js
Surfboard๋ ./test/ ํด๋์ ํ ์คํธ ํ์ผ์ ์์งํ๊ณ Surfboard.config.json์ ๊ตฌ์ฑ๋ ๋ ธ๋์์ ์คํฌ๋ฆฝํธ๋ฅผ ์คํํฉ๋๋ค. ๋ช ์ด ํ์ ๋ค์๊ณผ ๊ฐ์ ๋ด์ฉ์ด ํ์๋ฉ๋๋ค.
wallet test suite
Generating accounts with nonce: ce8d86ee
Account generated: foofoofoofoofoofoofoofoofoofoofoo#ce8d86ee - 3M763WgwDhmry95XzafZedf7WoBf5ixMwhX
Account generated: barbarbarbarbarbarbarbarbarbar#ce8d86ee - 3MAi9KhwnaAk5HSHmYPjLRdpCAnsSFpoY2v
Account generated: wallet#ce8d86ee - 3M5r6XYMZPUsRhxbwYf1ypaTB6MNs2Yo1Gb
Accounts successfully funded
Script has been set
โ Can deposit (4385ms)
โ Cannot withdraw more than was deposited
โ Can withdraw (108ms)
3 passing (15s)
๋ง์ธ! ํ
์คํธ๊ฐ ํต๊ณผ๋์์ต๋๋ค. ์ด์ Waves Explorer๋ฅผ ์ฌ์ฉํ ๋ ์ด๋ค ์ผ์ด ๋ฐ์ํ๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค. ๋ธ๋ก์ ๋ณด๊ฑฐ๋ ์์ ์ฃผ์ ์ค ํ๋๋ฅผ ๊ฒ์์ ๋ถ์ฌ๋ฃ์ต๋๋ค(์: ํด๋น wallet#
. ๊ฑฐ๊ธฐ์์ ๊ฑฐ๋ ๋ด์ญ, dApp ์ํ, ๋์ปดํ์ผ๋ ๋ฐ์ด๋๋ฆฌ ํ์ผ์ ์ฐพ์ ์ ์์ต๋๋ค.
์จ์ด๋ธ ์ต์คํ๋ก๋ฌ. ๋ฐฉ๊ธ ๋ฐฐํฌ๋ ์ ํ๋ฆฌ์ผ์ด์
์
๋๋ค.
๋ช ๊ฐ์ง ์ํ๋ณด๋ ํ:
1. ํ ์คํธ๋ท ํ๊ฒฝ์์ ํ ์คํธํ๋ ค๋ฉด ๋ค์์ ์ฌ์ฉํ์ญ์์ค.
surfboard test --env=testnet
2. ํธ๋์ญ์ ์ JSON ๋ฒ์ ๊ณผ ๋ ธ๋์์ ์ฒ๋ฆฌ๋๋ ๋ฐฉ์์ ๋ณด๋ ค๋ฉด -v('verbose'๋ฅผ ์๋ฏธ)๋ฅผ ์ฌ์ฉํ์ฌ ํ ์คํธ๋ฅผ ์คํํฉ๋๋ค.
surfboard test -v
Waves Keeper์ ํจ๊ป ์ฑ ์ฌ์ฉํ๊ธฐ
1. Waves Keeper๊ฐ ์๋ํ๋๋ก ์ค์ ํฉ๋๋ค.
๋ก์ปฌ ๋
ธ๋์ ์๋ํ๋๋ก Waves Keeper ์ค์
2. ๋คํธ์ํฌ ํ ํฐ๊ณผ ํจ๊ป ๋น๋ฐ ๋ฌธ๊ตฌ๋ฅผ ๊ฐ์ ธ์ค์๊ฒ ์ต๋๊น? ๋จ์ํ๋ฅผ ์ํด ๋
ธ๋์ ์ด๊ธฐ ์๋๋ฅผ ์ฌ์ฉํฉ๋๋ค. waves private node seed with waves tokens
. ์ฃผ์: 3M4qwDomRabJKLZxuXhwfqLApQkU592nWxF
.
3. npm์ ์ฌ์ฉํ์ฌ ์๋ฒ๋ฆฌ์ค ๋จ์ผ ํ์ด์ง ์ ํ๋ฆฌ์ผ์ด์
์ ์ง์ ์คํํ ์ ์์ต๋๋ค. ๋๋ ๊ธฐ์กด ํญ๋ชฉ์ผ๋ก ์ด๋ํฉ๋๋ค.
4. dApp ์ฃผ์ ํ ์คํธ ์์์ ํ ์คํธ ์คํ์ ์ง๊ฐ ์ฃผ์(์ ๋ฐ์ค ์น ๋ถ๋ถ)๋ฅผ ์ ๋ ฅํ์ธ์.
5. "์ ๊ธ" ํ๋์ ์์ก์ ์ ๋ ฅํ๊ณ ๋ฒํผ์ ํด๋ฆญํ์ธ์:
Waves Keeper๋ 10 WAVES๋ฅผ ์ง๋ถํ๊ณ InvokeScriptTransaction์ ์๋ช
ํ ์ ์๋ ๊ถํ์ ์์ฒญํฉ๋๋ค.
6. ๊ฑฐ๋๋ฅผ ํ์ธํ์ธ์.
ํธ๋์ญ์
์ด ์์ฑ๋์ด ๋คํธ์ํฌ์ ๋ธ๋ก๋์บ์คํธ๋ฉ๋๋ค. ์ด์ ๊ทธ๋
์ ID๋ฅผ ๋ณผ ์ ์์ต๋๋ค
7. Waves Explorer๋ฅผ ์ฌ์ฉํ์ฌ ํธ๋์ญ์ ์ ๋ชจ๋ํฐ๋งํฉ๋๋ค. ๊ฒ์์ฐฝ์ ์์ด๋๋ฅผ ์ ๋ ฅํ์ธ์
๊ฒฐ๋ก ๋ฐ ์ถ๊ฐ ์ ๋ณด
Waves ํ๋ซํผ์์ ๊ฐ๋จํ dApp์ ๊ฐ๋ฐ, ํ ์คํธ, ๋ฐฐํฌ ๋ฐ ์ฌ์ฉํ๊ธฐ ์ํ ๋๊ตฌ๋ฅผ ์ดํด๋ณด์์ต๋๋ค.
- RIDE ์ธ์ด
- VS ์ฝ๋ ํธ์ง๊ธฐ
- ์จ์ด๋ธ ํ์๊ธฐ
- ์ํ ๋ณด๋
- ์จ์ด๋ธ ํคํผ
RIDE๋ฅผ ๊ณ์ ๋ฐฐ์ฐ๊ณ ์ถ์ ๋ถ๋ค์ ์ํ ๋งํฌ:
๊ณ์ํด์ RIDE ์ฃผ์ ์ ๋ํด ์์๋ณด๊ณ ์ฒซ ๋ฒ์งธ dApp์ ๋ง๋ค์ด๋ณด์ธ์!
TL; DR :
์ถ์ฒ : habr.com