소개
ICE(ICY 토큰)는 ICON 생태계의 확장 네트워크이자 애플리케이션 허브입니다.
서브스트레이트(Substrate)로 구축된 ICE는 서브스트레이트 SDK를 사용하여 기존 레이어-1 블록체인 프로토콜의 기능 세트를 확장한 최초의 네트워크입니다. 또한 ICE는 ICON 생태계에 EVM(Ethereum Virtual Machine / 이더리움 가상머신) 호환성을 추가로 제공합니다.
ICE는 또한 ICON의 BTP(ICON 블록체인 연결 / 인터체인 기술)에 최적화된 폴카닷(Polkadot) 생태계의 유일한 EVM 호환 파라체인이 될 것입니다. 이로써 ICE는 ICON의 BTP로 구동되는 업계 최고의 크로스-체인 애플리케이션을 선보이는 폴카닷 생태계 내에서 잠재적인 플래그십 체인으로 자리 잡을 것입니다.
이 튜토리얼 시리즈에서 우리는 Snow 블록체인의 현재 테스트넷(프로스트 네트워크(Frost Network))에서 작업할 것입니다. (Snow는 ICE의 카나리아 네트워크이고 쿠사마(Kusama)는 폴카닷의 카나리아 네트워크입니다.)
카나리아 네트워크 = 19세기 유럽의 광부들이 탄광에 들어갈 때 '호흡기가 약한 카나리아(새)'를 가지고 들어가서 메탄가스나 일산화탄소 같은 유해가스등의 위험을 감지하도록 한 것 (쿠사마가 그런 목적으로 만들어졌기에, 쿠사마를 폴카닷의 카나리아 네트워크로 불림)
시작하기 — Node.js와 Ethers
EVM을 지원하기 위해 이미 구축된 방대한 커뮤니티 자료들 덕분에 ICE를 시작하는 것은 정말 쉽습니다. 현재 Java, Python, JavaScript, Go, Rust, .NET, Delphi, Dart를 포함한 거의 모든 프로그래밍 언어로 블록체인과 상호 작용할 수 있습니다.
이 과정에서 우리는 높은 인기와 사용 용이성으로 JavaScript에 초점을 맞출 것입니다.
Installing Node.js
Node.js는 JavaScript로 작성된 프로그램을 실행하는 데 필요한 모든 것을 포함하는 런타임 환경입니다.
$ sudo apt install nodejs$ node --version
v14.17.0
Installing npm
Node Package Manager(npm)은 Node JavaScript 플랫폼용 오픈 소스 패키지 관리자입니다.
$ sudo apt install npm
$ npm --version
6.14.13
Ethers
ethers.js는 EVM 호환 블록체인과 해당 생태계가 상호 작용하기 위한 완전하고 컴팩트한 라이브러리를 목표로 하는 라이브러리입니다. 원래 ethers.io와 함께 사용하도록 설계되었으며 이후 더 범용 라이브러리로 확장되었습니다.
Installing Ethers
새 작업 폴더에서 다음을 실행합니다.
$ npm install --save ethers
이제 설정이 끝났으므로 이제 블록체인과 상호 작용할 수 있습니다. 이를 위해 노드 런타임 환경을 활용할 것입니다. node단순히 터미널에 입력하여 노드를 시작하십시오.
$ node
Welcome to Node.js v14.17.0.
Type ".help" for more information.
>
Importing Ethers
> const { ethers } = require(“ethers”);
쿼리를 작성하기 전에 블록체인 네트워크에 대한 연결을 위한 추상화를 제공하는 JavaScript 클래스 인 공급자 를 설정해야 합니다. 블록체인 및 해당 상태에 대한 읽기 전용 액세스를 제공합니다. 우리는 공급자로 Frost Testnet을 사용할 것입니다.
Querying the Blockchain
> const provider = new ethers.providers.JsonRpcProvider(“http://frost-rpc.icenetwork.io:9933");
//Get the current block number
> provider.getBlockNumber().then(res => console.log(res))
108981
참고: JS 약속이 터미널을 차단하는 경우 Enter 키를 누르십시오.
예를 들어 특정 블록 번호의 세부 정보를 얻을 수 있습니다.
//Get details of the block
> provider.getBlock(108981).then(res => console.log(res))
다음과 같은 출력을 제공합니다.
{
hash: '0xd6bbcb783700de1e3aa5e7e92b8c7d9f46f59593e2eb504b6b56f9e9e0e558fb',
parentHash: '0xfd6c4cbf33ae9fe425fa2ab71d5a633adf00d9152ca977871ab858561a2a99f5',
number: 108981,
timestamp: 1645193964,
difficulty: 0,
gasLimit: BigNumber { _hex: '0xffffffff', _isBigNumber: true },
gasUsed: BigNumber { _hex: '0x00', _isBigNumber: true },
miner: '0xBfF94C8C44Af38b8a92C1d5992D061D41f700C76',
extraData: '0x',
transactions: [],
_difficulty: BigNumber { _hex: '0x00', _isBigNumber: true }
}
이 시점에서 이미 블록체인에 몇 가지 쿼리를 수행할 수 있습니다. 이 링크를 사용하여 만들 수 있는 쿼리에 대해 탐색할 수 있습니다.
지갑 생성
//Creating a new wallet randomly
> const wallet = ethers.Wallet.createRandom()
//Create a new Wallet instance with existing privateKey
> const wallet = ethers.Wallet(privateKey)
//Print the wallet address
> wallet.address//Encrypting the wallet in JSON with password
> encrypted_json = wallet.encrypt('password_here')
//Saving the encrypted wallet
> const fs = require('fs')
> encrypted_json.then(json => fs.writeFileSync('wallet', json))
//Recovering the encrypted wallet
> let encrypted_wallet = fs.readFileSync('wallet', {encoding: 'utf8'})
//Replace password_here with the password you set for the wallet
> let wallet_ = ethers.Wallet.fromEncryptedJson(encrypted_wallet, 'password_here')
//Verify the recovered wallet is same as the one we created
> wallet_.then(w => w.address == wallet.address).then(res => console.log(res))
true
// NOTE: Press Enter key if JS promise blocks your terminal
EVM 기반 블록체인에서 가장 많이 사용되는 지갑인 메타마스크를 사용하여 지갑을 생성할 수도 있습니다. 메타마스크는 개인 키나 암호화된 지갑을 직접 사용하는 대신 기본적으로 BIP-39 니모닉 구문을 사용하여 지갑을 복구할 수 있습니다.
메타마스크로 새 지갑 을 만드는 방법은 이 글을 따라하세요.
// Create a wallet instance from a mnemonic (your wallet backup phrase)...
> backup_phrase = "<your_backup_phrase_here>"
> walletMnemonic = ethers.Wallet.fromMnemonic(backup_phrase)
테스트넷 토큰으로 지갑 자금 조달
이제 지갑 설정이 완료되었으므로 Frost Network에서 거래를 시작할 수 있습니다. 거래를 하기 전에 먼저 잔액을 확인하십시오.
> provider.getBalance(wallet.address).then(bal => console.log(bal))
BigNumber { _hex: ‘0x00’, _isBigNumber: true }
// NOTE: Press Enter key if JS promise blocks your terminal
앗! Frost 네트워크에서 거래를 하기 전에 지갑에 ICZ 잔액이 있어야 합니다.
그러나 우리는 당신을 덮었습니다. 디스코드 채널에 참여하고 메시지 상자에 다음 명령을 붙여 넣으면 테스트용 ICZ 토큰을 계정에 가져올 수 있습니다.
!send <evm_address>
예시: !send 0x7c0f5F59A22B657C8D9E21b44D2Dc0118fD2BE7B
Frost Network 수도꼭지에 대한 자세한 내용은 여기를 참조하십시오.
첫 거래 생성
수도꼭지에서 테스트 ICZ 토큰을 받은 후 잔액을 다시 확인할 수 있습니다.
> provider.getBalance(wallet.address).then(bal => console.log(bal))
BigNumber { _hex: ‘0x8ac7230489e7fe0c’, _isBigNumber: true }
// NOTE: Press Enter key if JS promise blocks your terminal
가스 요금을 충당하기에 충분한 토큰이 있으면 이제 거래를 시작할 수 있습니다.
메타마스크에서 가져온 지갑에 1 ICZ를 보내기 위한 트랜잭션 객체를 생성해 봅시다.
tx = {
to: walletMnemonic.address,
value: ethers.utils.parseEther(“1.0”)
}
거래를 구성할 때 ether에서 제공하는 유틸리티 라이브러리를 사용하여 사용자 친화적인 문자열(일반적으로 ether 표시)과 계약 및 수학이 의존하는 기계 판독 가능한 값(일반적으로 wei) 사이를 변환했습니다.
이제 실제로 프로스트 네트워크(테스트넷)에 트랜잭션을 보내봅시다.
> connected_wallet = wallet.connect(provider)
> connected_wallet.sendTransaction(tx)
//Output
{
nonce: 1,
gasPrice: BigNumber { _hex: '0x01', _isBigNumber: true },
gasLimit: BigNumber { _hex: '0x5208', _isBigNumber: true },
to: '0x71CB05EE1b1F506fF321Da3dac38f25c0c9ce6E1',
value: BigNumber { _hex: '0x0de0b6b3a7640000', _isBigNumber: true },
data: '0x',
chainId: 553,
v: 1141,
r: '0x49c14440b7a8b4493f2d3112c68944b27ab7b536de3b4e0a87f06e88b54122a1',
s: '0x10bcd3ab81dade5583ea478e68835730eeff2d8e6f1125692a92745bda8831d4',
from: '0x4821C4aa31DEdFE01C36ed9F9ebab8Ba98509516',
hash: '0x06455b1991ddfba24bb070f8d704bc778d223fee80b19e714fcba471b4cfe379',
type: null,
confirmations: 0,
wait: [Function (anonymous)]
}
여기에 있는 지침에 따라 트랜잭션이 실제로 진행 되었고 txHash가 프로스트 네트워크에 존재하는지 확인할 수 있습니다.
Ganache
Ganache는 신속한 Ethereum 및 Corda 분산 응용 프로그램 개발을 위한 개인 블록체인입니다. 전체 개발 주기에서 Ganache를 사용할 수 있습니다. 안전하고 결정적인 환경에서 dApp을 개발, 배포 및 테스트할 수 있습니다.
ICE는 EVM과 완전히 호환되는 블록체인이기 때문에 Ganache를 사용하여 로컬에서 스마트 컨트랙트를 배포하고 Ganache에서 제공하는 여러 사전 자금 지갑으로 테스트할 수 있습니다.
Installing Ganache
이 링크에서 Ganache를 다운로드하여 설치할 수 있습니다.
또는 npm으로 설치하기만 하면 됩니다.
$ npm install -g ganache
Starting Ganache
$ ganache
ganache v7.0.2 (@ganache/cli: 0.1.3, @ganache/core: 0.1.3)
Starting RPC server
Available Accounts
==================
(0) 0xb5A1FB0BA92D41783558f1BcC26d4B683A527898 (1000 ETH)
(1) 0x3773DF2125B277D9A68AfFe6D8aE64a0E1613CAB (1000 ETH)
(2) 0x77eF3259fb23945050826D71C94c6BaC4BC2f63d (1000 ETH)
(3) 0x2Cbd0BF569A17a41F3297e57ED83aebC8e2147D1 (1000 ETH)
(4) 0xD8306Cf8fcDcdA72F46f83E17d0119c468FE88AB (1000 ETH)
(5) 0x5438834965690b03547Dd8FC5EbF599d0E43E63C (1000 ETH)
(6) 0xf5Ae084abEFa5aFf3D851905710985Adb2a66518 (1000 ETH)
(7) 0xaE26fD20bd3BF1DC979Bc9F021FcCE35f500eab5 (1000 ETH)
(8) 0x6C1fb76696bc9b80c48D01359d171C98de743364 (1000 ETH)
(9) 0x548B4823b24c544D5B130EbD1Df611eAA03c7292 (1000 ETH)
Private Keys
==================
(0) 0x656ed25385551d2eb12eecefbd2caa4660862b344f3ef17d6b9cc1c6201f4f6f
(1) 0x29cd6d979c2334a090525c53b8c4ccb16b3148d5b7ca7fdedaaea8dd81d14f2b
(2) 0x9541df40c5af0ed39c3484ddf33614f2894b30fb0087f14c85faded025437042
(3) 0x6bf650f05f371f5cc6b924f0a4d02fd9ec3ffa9de8a830bd14a1d416bc92b95b
(4) 0xaa7dfc0423df51580d7dfd897e5186374d2f4256877312a4a35728e9ef9425e2
(5) 0x6ae5680df64775b64c1d826fc5ac026d4ac8d569db8e4b123097458dbd6ea952
(6) 0x7b6c88535839f0cc84c272f5c3a47c37de289539acd0560d9b05f57ced755e15
(7) 0x1376bdc04032cde0a1f6cab10abe13bdc3c7e07c3cf681b94176372369313bce
(8) 0x4c89b9af175d57b321945d7c9a67a33a5b27fb328a22023e66c483373bcfdbd4
(9) 0xa4d2b757328f5d82ce036b5ee2d5501b59ced8a979bb9e66579aa1fa97240c59
HD Wallet
==================
Mnemonic: knife because tribe ride confirm squeeze certain lava letter piano legend library
Base HD Path: m/44'/60'/0'/0/{account_index}
Default Gas Price
==================
2000000000
BlockGas Limit
==================
30000000
Call Gas Limit
==================
50000000
Chain Id
==================
1337
RPC Listening on 127.0.0.1:8545
새 로컬 공급자를 사용하여 새 공급자를 설정하고 이전에 실행한 것과 동일한 쿼리에서 실행을 시도할 수 있습니다.
> const local_provider = new ethers.providers.JsonRpcProvider();
> local_provider.getBlockNumber().then(blk => console.log(blk))
BigNumber { _hex: ‘0x00’, _isBigNumber: true }
로컬 블록체인에는 트랜잭션이 없었기 때문에 아직 블록0 에 있습니다. ganache 명령을 실행할 때 Ganache에서 제공하는 일부 개인 키를 사용하여 지갑을 로드하고 일부 트랜잭션을 수행하여 블록을 채우도록 합시다.
> wallet1 = new
ethers.Wallet(‘0x656ed25385551d2eb12eecefbd2caa4660862b344f3ef17d6b9cc1c6201f4f6f’)
> wallet2 = new
ethers.Wallet(‘0x29cd6d979c2334a090525c53b8c4ccb16b3148d5b7ca7fdedaaea8dd81d14f2b’)
//Verify that we have balance in thee wallet1
> local_provider.getBalance(wallet1.address).then(bal => console.log(bal))
BigNumber { _hex: ‘0x3635c9adc5dea00000’, _isBigNumber: true }
wallet1에서 wallet2로 10eth를 보내는 트랜잭션을 생성해 보겠습니다.
> tx = {
to: wallet2.address,
value: ethers.utils.parseEther(“10.0”)
}
이제 로컬 공급자와 연결하여 트랜잭션을 실행해 보겠습니다.
> wallet1 = wallet1.connect(local_provider)
> wallet1.sendTransaction(tx).then(res => console.log(res))
//Output
{
type: 2,
chainId: 1337,
nonce: 0,
maxPriorityFeePerGas: BigNumber { _hex: ‘0x9502f900’, _isBigNumber: true },
maxFeePerGas: BigNumber { _hex: ‘0x010c388d00’, _isBigNumber: true },
gasPrice: null,
gasLimit: BigNumber { _hex: ‘0x5208’, _isBigNumber: true },
to: ‘0x3773DF2125B277D9A68AfFe6D8aE64a0E1613CAB’,
value: BigNumber { _hex: ‘0x8ac7230489e80000’, _isBigNumber: true },
data: ‘0x’,
accessList: [],
hash: ‘0x8570ad95847a5c3743eea40db95e97757ebd094594a7a6a70a28e1017baf6754’,
v: 0,
r: ‘0x65d0acd6f38cf10fc8b9f6f6b9698780d0fad4790e6e754e8c61a0d3ee1ed8f2’,
s: ‘0x794d663e793c3450bde6ddccb47b6ba08e6ff9ee01067105ad01bd767aac7273’,
from: ‘0xb5A1FB0BA92D41783558f1BcC26d4B683A527898’,
confirmations: 0,
wait: [Function (anonymous)]
}
최신 블록 번호를 보면 지금은 1입니다.
> local_provider.getBlockNumber().then(blk => console.log(blk))
1
새로운 블록을 더 탐색하여 블록에 포함된 트랜잭션을 볼 수 있습니다.
> local_provider.getBlock(1).then(blk => console.log(blk))
{
hash: ‘0xe04bbe4c9727d711b0fc208258d333690f875568f960622ef9c7900810cd37a1’,
parentHash: ‘0x09ac6d90a50d8919b14321eecc6ee1eedcbee1c959fa456fa783600d1566f208’,
number: 1,
timestamp: 1644569590,
nonce: ‘0x0000000000000000’,
difficulty: 1,
gasLimit: BigNumber { _hex: ‘0x01c9c380’, _isBigNumber: true },
gasUsed: BigNumber { _hex: ‘0x5208’, _isBigNumber: true },
miner: ‘0x0000000000000000000000000000000000000000’,
extraData: ‘0x’,
transactions: [
‘0x8570ad95847a5c3743eea40db95e97757ebd094594a7a6a70a28e1017baf6754’
],
baseFeePerGas: BigNumber { _hex: ‘0x342770c0’, _isBigNumber: true },
_difficulty: BigNumber { _hex: ‘0x01’, _isBigNumber: true }
}
블록에 최근 거래만 포함되어 있음을 명확하게 확인할 수 있습니다.
요약
ICE 개발 시리즈의 첫 번째 부분에서 우리는 ICE 네트워크와 프로스트 네트워크(테스트넷)와 상호 작용하기 위한 Node.js 및 Ethers와 같은 설정 도구에 대해 알아 보았습니다. 우리는 또한 지갑을 만들고 자금을 조달하는 과정을 거쳤고 프로스트 테스트넷을 통해 하나의 계정에서 다른 계정으로 잔액을 이체하는 첫 트랜잭션를 활용했습니다. 마지막으로 Ganache를 사용하여 자체 로컬 프라이빗 블록체인을 배포하여 개발 프로세스를 더 쉽게 만들었습니다.
다음 파트에서는 솔리디티(Solidity / 이더리움 개발언어)를 사용하여 스마트 컨트랙트(dApp의 비즈니스 로직)을 작성하는 방법을 배워보겠습니다.
- [2024/11/12] 아이콘 개발 업데이트 - 10월 (2024.11.12 / ICON / ICX 코인 / 로드맵)
- [2024/11/12] 아이콘 개발 업데이트 - 10월 (2024.11.12 / ICON / ICX 코인 / 로드맵)
- [2024/03/06] 아이콘 개발 업데이트 - 2월 (2024.3.5 / ICON / ICX 코인 / 로드맵) (2)
- [2024/02/08] 아이콘 개발 업데이트 - 1월 (2024.2.8 / ICON / ICX 코인 / 로드맵)
- [2023/12/11] ICON이 낙관적이라고 생각하는 이유 - 트윗(X) 인용 (ICX / 아이콘 코인)
- [2023/12/09] ICON 개발 업데이트 - 11월 (2023.12.08 / 아이콘 / ICX 코인 / 로드맵)
- [2023/11/07] ICON 개발 업데이트 (2023.10 / 아이콘 / ICX 코인 / 로드맵)
[사용방법] ICE 네트워크 dApp 구축 튜토리얼 - 파트2: 스마트 컨트랙트
https://iconosphereio.medium.com/a-z-of-building-dapps-on-ice-part-2-smart-contracts-b6c0625d425c
[사용방법] ICE 네트워크 dApp 구축 튜토리얼 - 파트3: 보팅(Voting) dApp
https://iconosphereio.medium.com/a-z-of-building-dapps-on-ice-part-3-voting-dapp-25a13425f7de
[사용방법] ICE 네트워크 dApp 구축 튜토리얼 - 파트4: Ink! 스마트 컨트랙트들
https://iconosphereio.medium.com/a-z-of-building-dapps-on-ice-part-4-ink-smart-contracts-bdc2399390cf