์ด๋๋ฆฌ์ ๋ ธ๋๋ Geth๋ Parity๋ฅผ ์ฌ์ฉํ์ฌ ์ค์ ์ด๋๋ฆฌ์ ๋ฉ์ธ(๋๋ ํ ์คํธ) ๋คํธ์ํฌ์ ์ ์ํ์ฌ ๋ธ๋ก์ ๋ชจ๋ ๋๊ธฐํ์์ผ์ผ ํ๋ค. ๊ทธ๋ฌ๋ ๋ธ๋ก์ ๋๊ธฐํ ์ํค๋๋ฐ๋ง ํด๋ 2-3์ผ ์ ๋ ์์๋๋ฉฐ, ํธ๋์ญ์ ์ ๋ณด๋ด๋ ๋ธ๋ก์ ์ฑ๊ตดํ๊ธฐ๊น์ง ๊ธฐ๋ค๋ ค์ผ ํ๋ ๋ฑ, ์ค๋งํธ ์ปจํธ๋ํธ๋ฅผ ๊ฐ๋ฐ ํ ๋ ๋ถํธํ ์ ์ด ๋ง๋ค.
๊ทธ๋์ ์ค๋งํธ ์ปจํธ๋ํธ๋ฅผ ๊ฐ๋ฐ ํ ๋๋ ๊ฐ๋์(Ganache)์ ๊ฐ์ ๊ฐ์ ํน์ ํ๋ผ์ด๋น ๋คํธ์ํฌ ์์์ ์ค๋งํธ ์ปจํธ๋ํธ๋ฅผ ๊ตฌ๋ํด๋ณด๊ณ , ํ ์คํธ๋ท์ ๊ฑฐ์ณ ๋ฉ์ธ๋ท์ ์ฌ๋ฆฐ๋ค.
๊ฐ๋ฐ ๊ณผ์ ์ ๋ค์๊ณผ ๊ฐ๋ค.
TestRPC -> TestNet -> MainNet
๊ฐ๋์(Ganache)๋ ๊ฐ์์ ์ด๋๋ฆฌ์ ๋คํธ์ํฌ๋ฅผ ์์ฑํด์ ์ค๋งํธ ์ปจํธ๋ํธ๋ฅผ ์คํํ ์ ์๋๋ก ํด์ฃผ๋ ํ๋ก๊ทธ๋จ์ด๋ค.
๊ฐ๋์ ๋ฑ์ ์ด์ฉํด ๋ง๋ ๊ฐ์ ํ๊ฒฝ์ TestRPC๋ผ๊ณ ํ๋ค.
๋ค์ด๋ก๋ ํ ๊ฐ๋์น ์คํ ๋ช
๋ น์ด ./ganache-2.5.4-linux-x86_64.AppImage
Ganache๋ฅผ Quickstart๋ก ์คํ์ ํ๋ฉด ๋ค์ ํ๋ฉด์ด ๋์จ๋ค.
ํ๋ฉด์ ๋ํด์ ๊ฐ๋ตํ ์ค๋ช ํ๋ฉด
ํ์ฌ ๊ฐ์์ ์ด๋๋ฆฌ์ ๋คํธ์ํฌ๊ฐ ๋ก์ปฌ์ ์ด์๋๊ณ ์๋ค.
ํด๋น ๋คํธ์ํฌ์ ์ ์ํ๋ ค๋ฉด http://127.0.0.1:7545 ๋ก ์ ์ํ ์ ์๋ค.
10๊ฐ์ ๊ฐ์ ๊ณ์ ์๋ ๊ฐ๊ฐ 100 ์ด๋์ ์์ก์ด ์ถฉ์ ๋์ด ์๋ค.
Ganache์์ mining์ด ํ์ฑํ๋์ด์๊ธฐ ๋๋ฌธ์ ๋ฐ๋ก contract๋ฅผ ๋ฐฐํฌํ๊ฑฐ๋ transaction์ ์คํํ ์ ์๋ค.
์ดํ๋ฆฌ์ผ์ด์ ์ ์๋จ์ 4๊ฐ์ ํญ์ ๊ฐ๊ฐ ๋ค์๊ณผ ๊ฐ๋ค.
Accounts: account๋ค์ ์ฃผ์, ์๊ณ , ํธ๋์ญ์ ์
Blocks: block ๋ฒํธ, ์์ฑ์์ , ์ฌ์ฉ๋ ๊ฐ์ค, ํฌํจ๋ ํธ๋์ญ์
Transactions: ์ ์ฒด ํธ๋์ญ์
Contracts : ํธ๋ฌํ(Truffle) ํ๋ก์ ํธ์ ํฌํจ๋ ์ค๋งํธ ์ปจํธ๋ํธ
Events : ์ด๋ฒคํธ ๋ฆฌ์คํธ
Logs: EthereumJS VM์ ๋ก๊ทธ
GUI๊ฐ ํ์์๋ค๋ฉด ganache-cli์ ์ฌ์ฉํ ์ ์๋ค.
Truffle์ ์ฌ์ฉํ์ฌ ๊ฐ๋ฐ/ํ
์คํธ ํ๊ฒฝ์ ๊ตฌ์ฑํ ๊ฒฝ์ฐ, truffle develop๋ช
๋ น์ผ๋ก ganache-cli ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
Remix๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๋ฐ/ํ
์คํธ ํ๊ฒฝ์ ๊ตฌ์ฑํ ๊ฒฝ์ฐ, MetaMask์์ ๋ก์ปฌ ๋คํธ์ํฌ๋ก ์ฐ๊ฒฐํ์ฌ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
์ด ๋ฐฉ๋ฒ์ ๊ฐ๋ฐ ๋ฐ ๋ฐฐํฌ๊ณผ์ ์์ TestNet์ ํด๋นํ๋ ๊ณผ์ ์ด๋ค.
Remix๋ฅผ ์ด์ฉํ์ฌ TestRPC์์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์.
Metamask ๊ณ์ ์ ์ด์ฉํ์ฌ Remix ๊ณ์ ๊ณผ ์ฐ๋ํ๋ค. ERC-20 ํ ํฐ ์ฝ๋๋ฅผ ์ค๋นํ๋ค.
Ganache ๋คํธ์ํฌ์ ERC-20 ํ ํฐ์ ๋ฐฐํฌํ๋ค.
Deployํ Ganache๋ฅผ ๋ณด๋ฉด Current Block์ด 0์ด์์ง๋ง ํ๋์ ๋ธ๋ก์ด ์์ฑ๋์๋ค.
Deploy์ ๋์์ transaction์ Ganache ๊ฐ์ ๋คํธ์ํฌ์ ์ ์กํ๊ณ , ์ฑ๊ตด์ด ์ผ์ด๋์ ๋ธ๋ก์ด 1๊ฐ ์์ฑ๋ ๊ฒ์ด๋ค.
Ropsten TestNet์์ ์ฌ์ฉํ๋๊ฒ ์ฒ๋ผ ๋คํธ์ํฌ์์ ํจ์๋ฅผ ์คํ ๊ฐ๋ฅํ ๋ชจ์ต์ ๋ณผ ์ ์๋ค.
Transaction์ ๋๋ฌ์ ๋ค์ด๊ฐ๋ฉด ๋ฐฉ๊ธ Deploy๋ฅผ ํ๋ฉด์ ๋ฐ์์ํจ transaction์ด ๋ค์ด ์๋ค. ์ด๋ ๊ฒ ์ค๋งํธ ์ปจํธ๋ํธ๊ฐ Ganche ๋คํธ์ํฌ์ ๋ฐฐํฌ๋ ๊ฒ์ ํ์ธ ํ ์ ์๋ค.
Metamask์์ Ganache์ ๋ฐฐํฌํ ํ ํฐ ์ฃผ์๋ฅผ ์ด์ฉํด ํ ํฐ์ ์ถ๊ฐํ๋ค.
์ถ๊ฐ๋ ํ ํฐ์ ๋ค๋ฅธ ๊ณ์ ์ผ๋ก ์ ์กํด๋ณธ๋ค.
Ganache ๋คํธ์ํฌ๋ ๋ก์ปฌ ๋คํธ์ํฌ ํ๊ฒฝ์ผ๋ก, ๋ค๋ฅธ ๋คํธ์ํฌ์ ์๋ ๊ณ์ ์ผ๋ก ์ ์ก์ด ๋ถ๊ฐ๋ฅํ๋ค.
Metamask์์ ์๋ก์ด ๊ณ์ ์ ๋ง๋ค์ด ์ ์กํด๋ณด์.
๋ค๋ฅธ ๊ณ์ ์์ ํ ํฐ์ ๋ฐ์๊ฒ์ ํ์ธ ํ ์ ์๋ค.
Ganache๋ฅผ ํ์ธํ๋ฉด ๋ธ๋ก์ด ํ๋ ๋ ์ฑ๊ตด์ด ๋์ด ํธ๋์ญ์ ์ด ์๊ธด๊ฒ์ ํ์ธ ํ ์ ์๋ค.
ํ ํฐ์ ๊ฐ์๋ฅผ remix์์ balanceOf ํจ์๋ก ํ์ธํด๋ณด์.
์ํ ๋ณ์๊ฐ ๋ณํ๋ "์ฐ๊ธฐ" ๋ช ๋ น์ ์ํํ ๋์๋ง ์ฑ๊ตด์ด ์ผ์ด๋๊ธฐ ๋๋ฌธ์ ์ฝ๊ธฐ ์ ์ฉ ํจ์์์๋ ์ฑ๊ตด์ด ์ผ์ด๋์ง ์๋๋ค.
truffle ํ๋ ์์ํฌ๋ ์ค๋งํธ ์ปจํธ๋ํธ(solidity) ๊ฐ๋ฐ์ ๊ฐ๋ฐ, ๋ฐฐํฌ ๋ฐ ํ
์คํธ ํ๊ฒฝ์ ์ ๊ณต ํ๋ค.
์ด ํ๋ ์์ํฌ๋ node.js์์ ๋์์ ํ๋ฉฐ npm ์ผ๋ก ์ค์น๋ฅผ ํ ์ ์๋ค.
์๊ตฌ์ฌํญ
npm install -g truffle
์ค์น ํ truffle์ ์คํํ์๋ฉด ๋ช ๋ น์ด๋ฅผ ํ์ธ ํ ์ ์๋ค.
Truffle ๊ณต์ ๋ฌธ์์์๋ ํ์ธ ํ ์ ์๋ค.
https://trufflesuite.com/docs/truffle/overview
๋ค์ ๋ช ๋ น์ด๋ฅผ ํตํด Truffle Sample Project๋ฅผ ๋ง๋ค์ด๋ณด์.
mkdir sample
cd sample
truffle init //sample ํด๋์์ truffle init์ ํตํด ํธ๋ฌํ ํ๋ก์ ํธ๋ฅผ ์ด๊ธฐํํ๋ค.
์ ์์ ์ผ๋ก ์ํ์ด ๋๋ฉด ๋ค์์ ํด๋ ๊ตฌ์กฐ๋ก ์์ฑ์ด ๋๋ค.
TRUFFLE DEVELOP์ truffle์์ Ganache์ ๊ฐ์ ๊ธฐ๋ณธ์ผ๋ก ์ ๊ณตํ๋ ์ด๋๋ฆฌ์ ํด๋ผ์ด์ธํธ์ด๋ค.
truffle develop
์ ๋ช
๋ น์ด๋ฅผ ํ๋ก์ ํธ ๋ฃจํธํด๋(sample ํด๋)์์ ์คํํ๋ฉด 10๊ฐ์ Accounts์ Private Keys ๊ฐ ๋ฆฌ์คํธ์
๋๋ฉด์ truffle(develop)> ํ๋กฌํํธ๊ฐ ๋ํ๋๊ฒ ๋๋ค. ๋ํ JSON-RPC์ฉ(http://127.0.0.1:9545/) ์๋น์ค๊ฐ ์ ๊ณต๋๋ค. truffle console๋ก ์
์ฅํ๊ฒ ๋๋๋ฐ ์ฝ์์ ์ข
๋ฃํ๊ธฐ ์ํด์๋ .exit ์
๋ ฅํ๋ฉด ์ฝ์์ด ์ข
๋ฃ๋๋ค.
์ด์ ์ ๋ฐฐ์ ๋ Ganache์ ๊ฐ์ ์ญํ ์ ํ๋ ์ด๋๋ฆฌ์ ํด๋ผ์ด์ธํธ์ด๋ค.
Ganache์์ ๋ฐฐ์ ๋ ๋ฐฉ๋ฒ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก MetaMask์ ๊ณ์ ์ ์ฐ๋ํ์ฌ ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
์ด๋๋ฆฌ์ ๋คํธ์ํฌ์๋ ๋คํธ์ํฌ ID์ ์ฒด์ธ ID์ ๋ ๊ฐ์ง ์๋ณ์๊ฐ ์๋ค๊ณ ํ๋ค. ๋คํธ์ํฌ๋ฅผ ์ถ๊ฐํ ๋, Truffle ๋คํธ์ํฌ ์ญ์ ์ฒด์ธID๋ฅผ ๊ธฐ์
ํด์ผ ํ๋๋ฐ ์ฒด์ธ ID์ ๋คํธ์ํฌ ID์ ์ฐจ์ด์ ๊ณผ ์ด๋์ ์ฌ์ฉํ๋์ง ์ ํ์ด ํ์
ํ๊ธฐ ์ด๋ ค์ ๋ค. ์ผ๋จ ์คํ์ค๋ฒํ๋ก์ฐ์ ๊ฒ์ํ ๊ฒฐ๊ณผ ์ด๋ Ganache ์ธก์ ์๊ณ , Truffle ์ธก์์๋ Truffle ๊ตฌ์ฑ ํ์ผ(truffle.js ๋๋ truffle-config.js)์ ํตํด ํน์ ๋คํธ์ํฌ ID๋ฅผ ํํฐ๋งํ ์ ์๋ค๊ณ ํ๋ค. ์ค์ ๋ก ์ฒด์ธID๋ 1337๋ก Ganache์ ๊ฐ์๊ณ , ์ด ์ ์ ๋ฏธ๋ฃจ์ด ๋ณด์ ์ผ๋จ์ Truffle ํ๋ ์์ํฌ๊ฐ ๋ณ๋์ ํ
์คํธ๋ท์ ์ฌ์ฉํ๋ ๊ฒ์ด ์๋๋ผ Ganache ํ
์คํธ ๋ท์ ์ฌ์ฉํ๋ค๋ ๊ฒ์ ํ์ธํ ์ ์์๋ค.
๋ ธ๋ ๊ฐ์ P2P ํต์ ์ย ๋คํธ์ํฌ IDย ๋ฅผ ์ฌ์ฉํ๋ ๋ฐ๋ฉด ํธ๋์ญ์ ์๋ช ํ๋ก์ธ์ค๋ย ์ฒด์ธ IDย ๋ฅผ ์ฌ์ฉํ๋ค.
EIP-155ย ๋ ํธ๋์ญ์ ์ฌ์ ๊ณต๊ฒฉ์ผ๋ก๋ถํฐ ๋ณดํธํ๊ธฐ ์ํด ํธ๋์ญ์ ์๋ช ํ๋ก์ธ์ค์ ์ผ๋ถ๋ก ์ฒด์ธ ID๋ฅผ ์ฌ์ฉํ์ฌ ๋์ ๋์๋ค.
https://besu.hyperledger.org/en/stable/Concepts/NetworkID-And-ChainID/
https://ethereum.stackexchange.com/questions/76581/what-is-the-networkid-and-chain-id-of-truffle-cli
truffle(develop)> compile
์ ๋ช ๋ น์ด ์คํ์ ํ๋ก์ ํธ ๋ฃจํธ ํด๋์ /build ํด๋๊ฐ ์์ฑ์ด ๋๋ฉฐ contracts ํด๋ ์๋์ ์๋ solidity ํ์ผ์ด json ํํ๋ก ๋ณ๊ฒฝ๋์ด ์์ฑ์ด ๋๋ค.
truffle(develop)> migrate
์ ๋ช ๋ น์ด ์คํ์ /build ํด๋์ ์์ฑ๋ ํ์ผ์ ์๋ฒ์ ๋ฐฐํฌ๊ฐ ๋๋ค.
truffle(develop)> test
์ ๋ช ๋ น์ด ์คํ์ /test ํด๋์ ์๋ .js , .sol ํ์ผ์ ์คํํ์ฌ ํ ์คํธ๋ฅผ ์ํํ๋ค.
Solidity ํ์ผ๋ก ํ ์คํธ ํ์ผ์ ์์ฑ์์ ํ์ผ๋ช ์ contract ๋ช ๊ณผ ์ผ์น ํ๊ฒ ํ๋ฉฐ, contract name์ Test~ ๋ก ์์ํ๊ณ , ํจ์๋ช ๋ test~ ๋ก ์์ ํ์ฌ์ผ ํ๋ค.
๊ฐ๋จํ ์ค๋งํธ ์ปจํธ๋ํธ๋ฅผ ์์ฑํด๋ณด์.
contracts/Sample.sol ํ์ผ์ ์์ฑํ์ฌ ํด๋น ํ์ผ์ ๊ฐ๋จํ ์ค๋งํธ ์ปจํธ๋ํธ ๋ด์ฉ์ ์ ์ฅ ํ๋ค.
์ฝ๋ ๋งจ์์ ๋ผ์ด์ผ์ค ์๋ณ์ ์ฌ์ฉํด์ผํจ
// SPDX-License-Identifier: MIT
migrations/2_deploy_sample.js ํ์ผ์ ์์ฑํ๋ค.
์ปจํธ๋ํธ๋ฅผ ํธ์ถํ ๋๋ ํ์ผ๋ช
์ด ์๋ ์ปจํธ๋ํธ๋ช
์ผ๋ก ๋ถ๋ฌ์จ๋ค.
๋ฐฐํฌํ์ผ์ ํ์ธํ๋ฉด ํ์ผ๋ช
์์ ์ซ์๊ฐ ๋ถ์ด ์๋ค.
migrations ํด๋ ์๋์ ํฌํจ๋ ๋ชจ๋ ํ์ผ์ ์คํ ํ๊ธฐ ๋๋ฌธ์ ๋ฐฐํฌ์ ์ฐ์ ์์๋ฅผ ์ฃผ๊ธฐ ์ํด ์์ ์ซ์๋ฅผ ๋ถ์ฌ ์ค๋ค.
test/TestSimpleStorage.sol ํ์ผ์ ์์ฑํ๋ค.
์ ์ฝ๋๋ฅผ ์ค๋นํ๋ฉด ํ
์คํธ ๊ณผ์ ์ด ๋ชจ๋ ์ค๋น๊ฐ ๋๋ค.
์ด์ ์ปดํ์ผ ํ Ethereum Client(Truffle Develop)์ ๋ฐฐํฌํ๊ณ ํ
์คํธ๊น์ง ๊ณผ์ ์ ์งํํ๋ค.
truffle(develop)> compile
truffle(develop)> migrate
truffle(develop)> test
Using network 'develop'.
Compiling ./contracts/Storage.sol...
Compiling ./test/TestSimpleStorage.sol...
Compiling truffle/Assert.sol...
Compiling truffle/DeployedAddresses.sol...
TestSimpleStorage
โ testSimpleStorage (57ms)
1 passing (589ms)
ํ ์คํธ ๊ณผ์ ์์ ๋ช ๊ฐ์ง ์๋ฌ๊ฐ ์์๋ค. ๊ฑฐ์ 2์๊ฐ๋์ ์ฝ์งํ๋ค.. ์ง์ง....
๊ฒฐ๊ตญ ํ ์คํธํ์ผ์ ์๋์ ๋ชจ๋๋ค์ ๋ถ๋ฌ์ค์ง ๋ชปํ๋ ์๋ฌ๋ ํธ๋ฌํ ๋ฒ์ v5.4.30 ์ผ๋ก ๋ณ๊ฒฝ ํ๋ ๊ฒ ์ผ๋ก ํด๊ฒฐํ๋ค.
import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/Storage.sol";
์ ํ๋ฉด ํ์ธ์ ํตํด truffle develop์ ๋ฐฐํฌ, ํ ์คํธ๊น์ง ์๋ฃํ๋ค.
Ganache ์ฐ๋์ ์ํด ๋คํธ์ํฌ ์ค์ ์ ํด์ผํ๋ค.
truffle-config.js ํ์ผ์ ๊ฐ๋จํ ์์ ํ๋ค.
development: {
host: "127.0.0.1",
port: 7545,
network_id: "5777",
},
์์ ํ truffle networks ํ์ธ์ ์งํํ๋ค.
development ๋คํธ์ํฌ๊ฐ ๊ธฐ๋ณธ์ผ๋ก ๋ฑ๋ก๋๊ฒ์ ํ์ธ ํ ์ ์๋ค.
์ด์ ์ ๊ฐ๋ฐ์ ์งํํ๋ ํ์ผ์ ๊ทธ๋๋ก Ganache ๋คํธ์ํฌ์ ์ ๋ฐ์ดํธ ํด๋ณด์.
Ganache ํ๋ก๊ทธ๋จ์ด ์คํ๋ผ์๋(7545ํฌํธ ๋คํธ์ํฌ๊ฐ ์ด๋ ค์๋) ์ํ์์ truffle compile
truffle migrate
๋ช
๋ น์ด๋ฅผ ํตํด Ganache ๋คํธ์ํฌ์ ์
๋ฐ์ดํธํ๋ค.
ํธ๋์ญ์ ์ด ๋ฐฐํฌ๋๊ณ , ๋ธ๋ก๋ ์์ฑ๋๊ฒ์ ํ์ธํ ์ ์๋ค.
ํธ๋์ญ์
ํ๊ฐ๋น ๋ธ๋ก 1๊ฐ ์์ฑ ์ด4๊ฐ๊ฐ ์์ฑ๋์๋๋ฐ ์ปจํธ๋ํธ ํธ์ถ ํธ๋์ญ์
์ ์ด๋ป๊ฒ ํธ์ถ๋๋์ง ์์ง ์ ์ดํด๊ฐ ๊ฐ์ง ์๋๋ค.
์คํ์ ํ๋ฆฐ์ ์๋ฆฌ๋ํฐ ๊ธฐ๋ฐ์ ์ค๋งํธ ์ปจํธ๋ํธ๋ฅผ ๊ฐ๋ฐํ๋ ํ๋ ์์ํฌ์ธ ์คํ์ ํ๋ฆฐ(OpenZeppelin)๊ณผ, ์ค๋งํธ ์ปจํธ๋ํธ๋ฅผ ๊ด๋ฆฌํ๊ณ ์ด์ํ๋ ํ๋ซํผ์ธ ์ ํ๋ฆฐOS๋ฅผ ์ ๊ณตํ๊ณ ์๋ค.
ํ ์คํธ๋ฅผ ์ํ ์๋ก์ด ํด๋๋ฅผ ๋ง๋ ๋ค.
mkdir openZeppelinSample
cd openZeppelinSample
truffle init
openZeppelinSample ํด๋๋ฅผ ๋ง๋ค๊ณ truffle init์ ํตํด ํธ๋ฌํ ๊ธฐ๋ฐ ํ๋ก์ ํธ ์ด๊ธฐํ๋ฅผ ์งํํ๋ค.
์๋ฆฌ๋ํฐ ์ฌ์ฉ์ ์ํ openzeppelin solidity ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ค์นํ๋ค.
npm install -E openzeppelin-solidity
gyp ERR! stack Error:
make
failed with exit code: 2 ์๋ฌ
git init, npm init์ผ๋ก ํด๊ฒฐ
node_modules ์์ openzeppelin-solidity ๋ด๋ถ ๊ตฌ์กฐ๋ฅผ ํ์ธํ ์ ์๋ค.
4. ๋ง์ฝ ์๋ฆฌ๋ํฐ ๋ฒ์ ์ด openzepellin ๋ฒ์ ๊ณผ ๋ค๋ฅด๋ค๋ฉด truffle-config.js๋ฅผ ์์ ํ๋ค.
compilers : {
solc : {
version : "0.8.10",
}
}
ZeppelinTestToken.sol ํ์ผ์ ์์ฑํ๋ค.
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.10;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract ZeppelinTestToken is ERC20 {
constructor() ERC20("ZeppelinTestToken", "ZTT") {
_mint(msg.sender, 100000000e18);
}
}
migrations ํด๋ ์์ 2_deploy_ZeppelinTestToken.js๋ฅผ ์์ฑํ๋ค.
var ZeppelinTestToken = artifacts.require("ZeppelinTestToken");
module.exports = function(deployer) {
deployer.deploy(ZeppelinTestToken);
};
๋ฐฐํฌ๋ฅผ ํ๊ธฐ์ ์ฌ์ฉํ openzeppelin/contract ๊ฒฝ๋ก๋ฅผ ์ถ๊ฐํ๋ค.
ZeppelinTestToken.sol ํ์ผ์ ์ฝ๋๋ฅผ ์ดํด๋ณด๋ฉด import๋ฅผ ํตํด ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์กด์ฌํ๋ ERC20.sol ํ์ผ์ ๊ฐ์ ธ์์ ์ฌ์ฉํ ์ ์๋ค.
์ดํ ๋ฐฐํฌ๋ฅผ ์งํํ์ฌ Ganache์์ ๋ธ๋ก ์์ฑ๊ณผ Metamask๋ฅผ ํ์ฉํ ํ ์คํธ๋ฅผ ์ค์ํ๋ค.
truffle migrate
ํ ์คํธ๊ฒฐ๊ณผ Ganache ํ ์คํธ๋ท์์ ๋ฉํ๋ง์คํฌ์ ์ง๊ฐ ์ถ๊ฐ, ZTT ํ ํฐ ์ถ๊ฐ, ํ ํฐ ์ ์ก ๋ชจ๋ ์ ์๋ํ๋ค.
ํด๋ ์ดํผ์ ์ด๋๋ฆฌ์ ๊ธฐ๋ฐ ํ๋ซํผ์ผ๋ก, ์ด๋๋ฆฌ์์ ์์คํ ๊ณผ ๋ง์ด ๋น์ทํ๋ค.
์ด๋๋ฆฌ์์ ์๋ MyEtherWallet๊ณผ ๊ฐ์ด, ํด๋ ์ดํผ์๋ Klaytn Wallet์ด๋ผ๋ ์น ์ง๊ฐ์ด ์๋ค.
Klaytn Wallet์์ ์ ๊ณตํด์ฃผ๋ Key ํ์ผ์ ํตํด MyEthereWallet๊ณผ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ฌ์ฉํ ์ ์๋ค.
๋ํ, ์ด๋๋ฆฌ์์ ์๋ MetaMask์ ๊ฐ์ด, ํด๋ ์ดํผ์๋ Kaikas Wallet์ด ์๋ค.
Kaikas Wallet์ ๊ธฐ๋ณธ ๊ตฌ์ฑ์ Metamask์ ๋น์ทํ๋ค. UI/UX ์์น๋ง ๋ณ๊ฒฝ๋์๊ณ ์ฌ์ฉ ๊ฐ๋ฅํ ํํ๋ ๋์ผํ๋ค.
ํด๋ ์ดํผ์ ์ค๋งํธ ์ปจํธ๋ํธ ์ธ์ด๋ก ์๋ฆฌ๋ํฐ๋ฅผ ์ฌ์ฉํ๋ฉฐ, ํ์ฌ ๋ฉ์ธ๋ท์ ์ ์ฉ๋ ์๋ฆฌ๋ํฐ ๋ฒ์ ์ 0.5.6 ๋ฒ์ ์ด๋ค.Klaytn IDE : https://ide.klaytn.com/
Klaytn IDE๋ 2022๋ 1์ 6์ผ์ ๊ธฐ์ ์ผ๋ก ํ์ฌ Remix ๋ฒ์ ๊ณผ ๋์ผํ๊ฒ ์ ๋ฐ์ดํธ๋์๋ค.
๋ฉ์ธ๋ท๊ณผ ํ ์คํธ๋ท์์ ์ฌ์ฉํ ์ ์๋ ์๋ฆฌ๋ํฐ ๋ฒ์ ์ ํ ์คํธ๋ท๊ณผ ๋ฉ์ธ๋ท์ ์์๋ก ์ ๊ทธ๋ ์ด๋๊ฐ ์์ ๋์ด ์๋ค.
ํด๋ ์ดํผ์ ์ค๋งํธ ์ปจํธ๋ํธ ๋ํ Truffle๋ก ์ปดํ์ผํ๊ณ ๋ฐฐํฌํ ์ ์๋ค.
ํด๋ ์ดํผ ํธ๋ฌํ ์ฌ์ฉ๋ฒ: https://ko.docs.klaytn.com/smart-contract/ide-and-tools/truffle
๋จผ์ ํด๋ ์ดํผ์์ Truffle์ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ๊ฐ๋์์ ๊ฐ์ ์ญํ ์ ํ๋ EN ๋ ธ๋๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
๋ก์ปฌ EN ๋ ธ๋ ๋ฐฐํฌ ๋ฐฉ๋ฒ : https://ko.docs.klaytn.com/getting-started/quick-start/deploy-a-smart-contract#deploying-a-smart-contract-using-truffle
์๊ฒฉ EN ๋ ธ๋๋ก ๋ฐฐํฌ๋ฅผ ํ๊ธฐ ์ํด์๋ truffle-hdwallet-provider-klaytn ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํด์ผํ๋ค.
truffle-hdwallet-provider-klaytn ํ๋ ์์ํฌ : https://www.npmjs.com/package/truffle-hdwallet-provider-klaytn
Klaytn IDE๋ฅผ ์ฌ์ฉํ์ฌ Baobab Network์ ์ค๋งํธ ์ปจํธ๋ํธ๋ฅผ ๋ฐฐํฌํด๋ณด์.
๋ค์ ์ฝ๋๋ฅผ Klaytn IDE์ ์ ๋ ฅํ๋ค.
pragma solidity 0.5.6;
contract Count {
uint256 public count = 0;
function setCount(uint256 _count) public {
count = _count;
}
}
KLAY๋ฅผ ๋ฐ์ ๊ณ์ ์ IDE์ Importํ์ฌ Baobab Network์ ๋ฐฐํฌ๋ฅผ ์งํํ๋ค. Deploy์ ์ฑ๊ณตํ๋ฉด ํฐ๋ฏธ๋์ ๋ก๊ทธ์ ํจ๊ป ์ข์ธก ํ๋จ์ Deployed Contract๋ฅผ ๋ฐ๊ฒฌํ ์ ์๋ค.
์ปจํธ๋ํธ ์ปดํ์ผ๋ฌํ ๋์ EVM VERSION ์ค constantinople ๋ก ์งํํ์๋ค.
๊ณต์๋ฌธ์๋ฅผ ์ฐธ์กฐํ๋ค.
Klaytn์ Solidity๋ก ์์ฑ๋ ๊ณ์ฝ์ ์ง์ํ๋ฉฐ EVM์ ์ฝ์คํํฐ๋ ธํ ๋ฒ์ ๊ณผ ํธํ
ํด๋ ์ดํผ์ฉ ๋ธ๋กํ์๊ธฐ (;์ด๋์ค์บ๊ฐ์) ์์ ๋ฐฐํฌํ ํธ๋์ญ์ ์ ํ์ธํ ์ ์๋ค.
SetCount ํจ์์ Public์ผ๋ก ์ ์ธ๋ Count ๋ณ์๋ฅผ ํ์ธ ํ ์ ์๋ค. SetCount์ ์ซ์๋ฅผ ๋ฃ์ด ํธ๋์ญ์ ์ ์คํ์์ผ๋ณด๊ณ , Count ๋ณ์๋ฅผ ๋ถ๋ฌ์ ๊ฐ์ ์ซ์๋ฅผ ์ ๋ถ๋ฌ์ค๋์ง ํ์ธํด๋ณด์.
ํด๋ ์ดํผ์์๋ ์ด๋๋ฆฌ์์ ์กด์ฌํ๋ EIP์ ๋์ผํ KIP(Klaytn Improvement Proposals)๊ฐ ์กด์ฌํ๋ค. ๊ทธ์ค Fungible Token Standard์ ๋ํ ๋ด์ฉ์ KIP-7์์ ์ฐพ์ ์ ์๋ค.
KIP-7์ ERC-20์ ๊ธฐ๋ฐ์ผ๋ก ๋ง๋ค์ด์ง ๋ด์ฉ์ด๋ค.
// KIP7 Interface
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function safeTransfer(address recipient, uint256 amount, bytes data) external;
function safeTransfer(address recipient, uint256 amount) external;
function safeTransferFrom(address sender, address recipient, uint256 amount, bytes data) external;
function safeTransferFrom(address sender, address recipient, uint256 amount) external;
์์ ์ฝ๋๋ ๊ธฐ๋ณธ์ ์ธ KIP-7์ ์ธํฐํ์ด์ค ๋ชฉ๋ก์ด๋ค.
๋ํ ์คํ์ ํ๋ฆฐ์ฒ๋ผ ํด๋ ์ดํผ์์๋ ์ค๋งํธ ์ปจํธ๋ํธ ๊ฐ๋ฐ์ ์ํ ๊ณต์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ ๊ณตํ๋ค. ์์ ๋งํฌ ๋ฌธ์์์๋ KAS๋ผ๋ ํ๋ ์์ํฌ๋ฅผ ์ด์ฉํ์ฌ EN๋ ธ๋์ truffle๋ก ๋น๋ํ๋ ๋ฐฉ๋ฒ๋ ์๊ฐํ๊ณ ์๋ค. ์ด ๊นํ๋ธ์์ KIP-7์ ๋ํ ์ฝ๋๋ฅผ ์ฐพ์๋ณผ ์ ์๋ค. KIP-7.sol
KIP-7.sol ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ฐ๋จํ๊ฒ SimpleKlaytnToken๋ฅผ ๋ง๋ค์ด Baobab Network์์ ํ ํฐ์ ์ฌ์ฉํด๋ณด์
[SimpleKlaytnToken ์ปจํธ๋ํธ ์ฝ๋]
pragma solidity 0.5.6;
contract IKIP {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function transferFrom(address spender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 amount);
event Transfer(address indexed spender, address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 oldAmount, uint256 amount);
}
contract SimpleKlaytnToken is IKIP {
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) public _allowances;
uint256 public _totalSupply;
string public _name;
string public _symbol;
uint8 public _decimals;
constructor(string memory getName, string memory getSymbol) public {
_name = getName;
_symbol = getSymbol;
_decimals = 18;
_totalSupply = 100000000e18;
_balances[msg.sender] = _totalSupply;
}
function name() public view returns (string memory) {
return _name;
}
function symbol() public view returns (string memory) {
return _symbol;
}
function decimals() public view returns (uint8) {
return _decimals;
}
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view returns (uint256) {
return _balances[account];
}
function transfer(address recipient, uint amount) public returns (bool) {
_transfer(msg.sender, recipient, amount);
emit Transfer(msg.sender, recipient, amount);
return true;
}
function allowance(address owner, address spender) public view returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint amount) public returns (bool) {
uint256 currentAllownace = _allowances[msg.sender][spender];
require(currentAllownace >= amount, "ERC20: Transfer amount exceeds allowance");
_approve(msg.sender, spender, currentAllownace, amount);
return true;
}
function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
_transfer(sender, recipient, amount);
emit Transfer(msg.sender, sender, recipient, amount);
uint256 currentAllowance = _allowances[sender][msg.sender];
require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
_approve(sender, msg.sender, currentAllowance, currentAllowance - amount);
return true;
}
function _transfer(address sender, address recipient, uint256 amount) internal {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
uint256 senderBalance = _balances[sender];
require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
_balances[sender] = senderBalance - amount;
_balances[recipient] += amount;
}
function _approve(address owner, address spender, uint256 currentAmount, uint256 amount) internal {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
require(currentAmount == _allowances[owner][spender], "ERC20: invalid currentAmount");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, currentAmount, amount);
}
}
KIR-7 ์ฝ๋๋ฅผ Klaytn IDE์ ์ ๋ ฅํ๊ณ ์ปดํ์ผ ํ ๋ค์ Deploy์ name๊ณผ symbol์ ์ ๋ ฅ ํ Deployํ๋ค.
์ดํ์๋ ์ด๋๋ฆฌ์ remix๋ก ํ ์คํธ๋ท์ ์ด์ฉํด ํ ํฐ์์ฑํ ๋ฉํ๋ง์คํฌ์ ํ ํฐ์ ์ถ๊ฐํ ๊ฒ ๊ณผ ๋๊ฐ์ ๋ฐฉ์์ผ๋ก ์งํํ๋ฉด ๋๋ค.
๋ฐ์ค๋ฐฅ ํ ์คํธ๋ท์ ํ ํฐ์ด ์ ์์ ์ผ๋ก ์์ฑ ๋์๊ณ , Transfer Transaction์ ๋ฐ์์์ผ ํ ํฐ ์ ์ก๋ํ ์ ์์ ์ผ๋ก ์๋ํ๋ ๊ฒ์ ํ์ธ ํ ์ ์๋ค.