1. Giới thiệu
ICON là một nền tảng Blockchain 2.0 (có nhiều điểm tương đồng với Ethereum). ICON chạy các hợp đồng thông mình với giao thức đồng thuận là BFT-DPoS (Delegated Proof-of-Stake), đồng tiền mã hóa trên mạng ICON gọi là ICX.
Mục tiêu mà đội ngũ phát triển ICON hướng đến trong tương lai là kết nối giữa các mạng blockchain với nhau, giúp chúng dễ dàng trao đổi tài sản cũng như dữ liệu. Có một ví dụ mà đội ngũ phát triển của ICON đưa ra để so sánh việc kết nối được các mạng blockchain với nhau, cũng giống như việc ra đời của bộ giao thức TCP/IP giúp kết nối các mạng riêng với nhau thành mạng Internet toàn cầu. ICON mong muốn họ sẽ là TCP/IP của Blockchain
Bên giới là video giới thiệu về ICON từ đội ngũ nhà phát triển
2. Một số khái niệm cơ bản
Tài khoản
Giống như Ethereum, ICON cũng có 2 loại tài khoản đó là:
- Tài khoản người dùng (Externally Owned Accounts): Bắt đầu bằng hx, độ dài 20 bytes hex
- Tài khoản hợp đồng thông minh: Bắt đầu bằng cx, độ dài 20 bytes hex. Không có private key.
Giao dịch
Các loại giao dịch trên ICON
- Chuyển ICX
- Lưu data vào blockchain
- Deploy hay update SCORE
- Thay đổi state của SCORE
Lưu ý: Smart contract trên ICON được gọi là SCORE
Các tham số khi thực hiện một giao dịch:
from
: Địa chỉ tạo giao dịchto
: Địa chỉ nhận giao dịch (Khi deploy thì địa chỉ nhận làcx0000000000000000000000000000000000000000
)value
: Lượng ICX gửi đistepLimit
: Số step tối đa mà giao dịch có thể thực hiện (gần tương tự như gasLimit trong Ethereum)time stamp
: Thời gian tạo giao dịchnonce
: Số thứ tự giao dịch của tài khoản gửi (tương tự như nonce trong Ethereum)nid
: Network ID (Phân biệt giữa mainnet, testnet)data type
: Giúp phân biệt loại giao dịch. Gồm 3 giá trịcall
,deploy
vàmessage
. Với giao dịch chuyển ICX thông thường, data type sẽ được bỏ qua.data
: Nội dung giao dịch (có thể là các tham số truyền vào để gọi hàm trong contract)signature
: Chữ ký số của người gửi giao dịchtransaction hash
: Giá trị băm định danh giao dịch
Phí giao dịch
Step là đơn vị đo lường để tính phí giao dịch trên mạng ICON. Số lượng Step mà một giao dịch cần phụ thuộc vào lượng tài nguyên tính toán cần bỏ ra để thực hiện giao dịch đó. Tỷ giá ban đầu, 1 ICX = 100,000,000 Step. Tỷ giá này có thể được thay đổi nếu giá ICX tăng quá cao hoặc bị giảm xuống rất thấp.
Công thức tính step
Step = max ( ∑ βiSi + C, C )
Lưu ý: Số lượng step tối đa mà một giao dịch có thể tiêu thụ là 2.5 tỷ step
Với:
- Si là số lần thực hiện một lời gọi cụ thể nào đến đến hợp đồng thông minh.
- βi là số step sẽ được tiêu thụ với từng lời gọi cụ thể.
- C là số lượng step tối thiểu một giao dịch cần phải chi trả (Hằng số với giá trị 100.000)
Bên dưới là 2 bảng lần lượt mô tả các giá trị khả dĩ của Si và các giá trị step tiêu thụ với mỗi lời gọi tương ứng đến contract.
Chính sách hỗ trợ phí giao dịch cho người dùng
Bình thường, khi thực hiện giao dịch, người dùng sẽ chịu toàn bộ chi phí. Với ICON, đội ngũ phát triển đã thiết kế một tính năng cho phép chủ của contract có thể hỗ trợ một phần hoặc toàn bộ chi phí giao dịch khi người dùng gọi đến contract của họ.
Phần trăm phí hỗ trợ giao động từ 0 – 100% (nghĩa là có thể không hỗ trợ phí). Nếu bên phát triển contract muốn hỗ trợ phí cho người dùng, thì họ phải gửi trước vào contract 1 lượng ICX để đến khi người dùng gọi đến, lượng ICX này sẽ được khấu trừ vào phí giao dịch của người dùng tùy theo tỷ lệ.
Virtual Step
Virtual Step là hệ thống tính phí mới của mạng ICON dành cho chủ sở hữu contract. Nó được tạo ra hàng tháng tương ứng với số lượng ICX được gửi vào contract và khoảng thời gian ký gửi ICX vào contract đó. Ngoài việc hỗ trợ phí cho người dùng bằng ICX, chủ sở hữu SCORE có thể trả phí bằng Virtual Step. Điều này giúp chủ sở hữu contract giảm 1 phần gánh nặng chi phí cũng như khuyến khích tăng phần trăm hỗ trợ phí lên cao hơn cho người dùng.
Một số đặc điểm:
- Virtual Step và Step có tỷ lệ 1:1
- Virtual Step được tạo ra sau mỗi 1,296,000 blocks (1 tháng). Khi đó, các Virtual Step chưa dùng sẽ hết hạn.
- Không thể chuyển Virtual Step đi đâu cả.
- Phí hỗ trợ người dùng sẽ tiêu Virtual Step trước, nếu hết Virtual Step mới tiêu đến ICX
Tính toán Virtual Step
- Khi gửi ICX vào contract, cần thiết lập đặt số tiền gửi và thời hạn gửi.
- Thời gian gửi có thể được thiết lập từ tối thiểu là 1 tháng đến tối đa là 24 tháng.
- Số tiền gửi tối thiểu từ 5.000 ICX đến tối đa 100.000 ICX.
Tùy vào thời gian ký gửi ngắn hay dài mà số virutal step nhận được sau mỗi tháng sẽ khác nhau:
Ví dụ:
- Gửi 10.000 ICX vào với thời gian 1 tháng. Mỗi tháng nhận được 80,000,000,000 Virtual Step, tương đương với 8 % của số tiền gửi 10.000, là 800 ICX.
- Gửi 10.000 ICX vào với thời gian 24 tháng. Mỗi tháng nhận được 202,400,000,000 Virtual Step, tương đương với 20.24 % của số tiền gửi 10.000 ICX.
Lưu ý: Các chủ sở hữu contract sẽ phải chịu một khoản phạt nếu họ rút ICX đã ký gửi trước khi kết thúc khoảng thời gian định trước. Tiền phạt bằng tổng số Virtual Step được sử dụng trong thời gian trước đó.
ICON nodes
ICON nodes có 3 loại
- Peer: có thể tham gia vào giao thức đồng thuận, có thể tạo mới block trên mạng.
- Citizen: Đồng bộ hóa dữ liệu blockchain và chuyển tiếp giao dịch đến Peer.
- Light: Lưu các block header của mạng, thực hiện nhiệm vụ xác minh giao dịch.
3. Viết smart contract
SCORE trên ICON được viết bằng ngôn ngữ Python.
Trước tiên, các bạn cần cài công cụ tbears, tbears là một công cụ giúp init, deploy và tương tác với smart contract trên mạng ICON (tương tự như truffle bên Ethereum). Các cài đặt tbears các bạn có thể tham khảo tại đây
Hello world
Chúng ta sẽ bắt đầu vơi một smart contract đơn giản nhất
Bước 1: Khởi tạo
1 2 3 | <span class="token comment"># tbears init [project_name] [main_class_name]</span> tbears init hello HelloWorld |
Trong folder hello
mới tạo ra, chúng ta sẽ thấy 3 file
__init.py__
: Ban đầu rỗng, file này giúp trình thông dịch Python nhận folder này như 1 package.hello.py
: FIle chính, chứa logic của contractpackage.json
: File này gồm các thông tin cơ bản của contract như version, name, …
1 2 3 4 5 6 7 | <span class="token comment">// package.json</span> <span class="token punctuation">{</span> <span class="token string">"version"</span><span class="token operator">:</span> <span class="token string">"0.0.1"</span><span class="token punctuation">,</span> <span class="token string">"main_module"</span><span class="token operator">:</span> <span class="token string">"hello_world"</span><span class="token punctuation">,</span> <span class="token string">"main_score"</span><span class="token operator">:</span> <span class="token string">"HelloWorld"</span> <span class="token punctuation">}</span> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <span class="token comment"># hello-world.py</span> <span class="token keyword">from</span> iconservice <span class="token keyword">import</span> <span class="token operator">*</span> TAG <span class="token operator">=</span> <span class="token string">'HelloWorld'</span> <span class="token comment"># class HelloWorld kế thừa class IconScoreBase của thư viện iconservice</span> <span class="token keyword">class</span> <span class="token class-name">HelloWorld</span><span class="token punctuation">(</span>IconScoreBase<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token comment"># Hàm __init__ là hàm constructor của class, được gọi khi nào contract được deploy mới </span> <span class="token keyword">def</span> <span class="token function">__init__</span><span class="token punctuation">(</span>self<span class="token punctuation">,</span> db<span class="token punctuation">:</span> IconScoreDatabase<span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token boolean">None</span><span class="token punctuation">:</span> <span class="token builtin">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>__init__<span class="token punctuation">(</span>db<span class="token punctuation">)</span> <span class="token comment"># Hàm on_install chỉ được gọi 1 lần khi deploy contract lần đầu</span> <span class="token comment"># Khi contract được update thì nó không được gọi lại nữa</span> <span class="token keyword">def</span> <span class="token function">on_install</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token boolean">None</span><span class="token punctuation">:</span> <span class="token builtin">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>on_install<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment"># Hàm on_update được gọi khi contract được update </span> <span class="token keyword">def</span> <span class="token function">on_update</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token boolean">None</span><span class="token punctuation">:</span> <span class="token builtin">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>on_update<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment"># Hàm hello sẽ trả về thông điệp "Hello" bất cứ khi nào được gọi</span> <span class="token decorator annotation punctuation">@external</span><span class="token punctuation">(</span>readonly<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span> <span class="token keyword">def</span> <span class="token function">hello</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token builtin">str</span><span class="token punctuation">:</span> Logger<span class="token punctuation">.</span>debug<span class="token punctuation">(</span>f <span class="token string">'Hello, world!'</span><span class="token punctuation">,</span> TAG<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token string">"Hello"</span> |
Implement Token
ICON hỗ trợ implement nhiều chuẩn token khác nhau (có tham khảo từ các chuẩn ERC của Ethereum), các chuẩn token của ICON được gọi được định nghĩa tại đây
Ở ví dụ này, chúng ta sẽ thử implement chuẩn token IRC-2 là dạng Fungibles Token (IRC-2 được tham khảo từ 2 chuẩn ERC-20 và ERC-223 của Ethereum). Định nghĩa về chuẩn IRC-2 các bạn có thể tham khảo ở đây
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | tbears init sample-token SampleToken `<span class="token variable"><span class="token variable">`</span> <span class="token variable">`</span></span>`<span class="token variable"><span class="token variable">`</span>py <span class="token comment"># sample_token.py</span> from iconservice <span class="token function">import</span> * TAG <span class="token operator">=</span> <span class="token string">'SampleToken'</span> <span class="token comment">## Định nghĩa interface theo chuẩn IRC-2</span> class TokenStandard: @abstractmethod def name<span class="token punctuation">(</span>self<span class="token punctuation">)</span> -<span class="token operator">></span> str: pass @abstractmethod def symbol<span class="token punctuation">(</span>self<span class="token punctuation">)</span> -<span class="token operator">></span> str: pass @abstractmethod def decimals<span class="token punctuation">(</span>self<span class="token punctuation">)</span> -<span class="token operator">></span> int: pass @abstractmethod def totalSupply<span class="token punctuation">(</span>self<span class="token punctuation">)</span> -<span class="token operator">></span> int: pass @abstractmethod def balanceOf<span class="token punctuation">(</span>self, _owner: Address<span class="token punctuation">)</span> -<span class="token operator">></span> int: pass @abstractmethod def transfer<span class="token punctuation">(</span>self, _to: Address, _value: int, _data: bytes <span class="token operator">=</span> None<span class="token punctuation">)</span>: pass <span class="token comment"># Định nghĩa Interface TokenFallbackInterface</span> <span class="token comment"># Hàm tokenFallback được gọi khi có 1 lượng token được gửi vào địa chỉ contract (tương tự như fallback function xử lý việc nhận ICX)</span> class TokenFallbackInterface<span class="token punctuation">(</span>InterfaceScore<span class="token punctuation">)</span>: @interface def tokenFallback<span class="token punctuation">(</span>self, _from: Address, _value: int, _data: bytes<span class="token punctuation">)</span>: pass <span class="token comment"># Implement</span> class SampleToken<span class="token punctuation">(</span>IconScoreBase, TokenStandard<span class="token punctuation">)</span>: _BALANCES <span class="token operator">=</span> <span class="token string">'balances'</span> _TOTAL_SUPPLY <span class="token operator">=</span> <span class="token string">'total_supply'</span> _DECIMALS <span class="token operator">=</span> <span class="token string">'decimals'</span> <span class="token comment"># Event được emit khi hàm _transfer được gọi</span> @eventlog<span class="token punctuation">(</span>indexed<span class="token operator">=</span><span class="token number">3</span><span class="token punctuation">)</span> def Transfer<span class="token punctuation">(</span>self, _from: Address, _to: Address, _value: int, _data: bytes<span class="token punctuation">)</span>: pass <span class="token comment"># Định nghĩa các biến cần lưu trữ trong contract</span> <span class="token comment"># </span><span class="token variable">`</span></span>_total_supply<span class="token variable"><span class="token variable">`</span> dạng int <span class="token punctuation">(</span>Tổng số token được tạo ra<span class="token punctuation">)</span> <span class="token comment"># </span><span class="token variable">`</span></span>_decimals<span class="token variable"><span class="token variable">`</span> dạng int, dùng để tính toán ra <span class="token variable">`</span></span>_total_supply<span class="token variable"><span class="token variable">`</span> <span class="token comment"># </span><span class="token variable">`</span></span>_balances<span class="token variable"><span class="token variable">`</span> dạng <span class="token punctuation">(</span>key <span class="token operator">=</span><span class="token operator">></span> value<span class="token punctuation">)</span> lưu số dư token của các tài khoản def __init__<span class="token punctuation">(</span>self, db: IconScoreDatabase<span class="token punctuation">)</span> -<span class="token operator">></span> None: super<span class="token punctuation">(</span><span class="token punctuation">)</span>.__init__<span class="token punctuation">(</span>db<span class="token punctuation">)</span> self._total_supply <span class="token operator">=</span> VarDB<span class="token punctuation">(</span>self._TOTAL_SUPPLY, db, <span class="token assign-left variable">value_type</span><span class="token operator">=</span>int<span class="token punctuation">)</span> self._decimals <span class="token operator">=</span> VarDB<span class="token punctuation">(</span>self._DECIMALS, db, <span class="token assign-left variable">value_type</span><span class="token operator">=</span>int<span class="token punctuation">)</span> self._balances <span class="token operator">=</span> DictDB<span class="token punctuation">(</span>self._BALANCES, db, <span class="token assign-left variable">value_type</span><span class="token operator">=</span>int<span class="token punctuation">)</span> <span class="token comment"># Tính toán số lượng token phát hành</span> <span class="token comment"># Tất cả lượng token ban đầu được nắm giữ bởi địa chỉ deploy contract</span> def on_install<span class="token punctuation">(</span>self, _initialSupply: int, _decimals: int<span class="token punctuation">)</span> -<span class="token operator">></span> None: super<span class="token punctuation">(</span><span class="token punctuation">)</span>.on_install<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">if</span> _initialSupply <span class="token operator"><</span> <span class="token number">0</span>: revert<span class="token punctuation">(</span><span class="token string">"Initial supply cannot be less than zero"</span><span class="token punctuation">)</span> <span class="token keyword">if</span> _decimals <span class="token operator"><</span> <span class="token number">0</span>: revert<span class="token punctuation">(</span><span class="token string">"Decimals cannot be less than zero"</span><span class="token punctuation">)</span> total_supply <span class="token operator">=</span> _initialSupply * <span class="token number">10</span> ** _decimals Logger.debug<span class="token punctuation">(</span>f<span class="token string">'on_install: total_supply={total_supply}'</span>, TAG<span class="token punctuation">)</span> self._total_supply.set<span class="token punctuation">(</span>total_supply<span class="token punctuation">)</span> self._decimals.set<span class="token punctuation">(</span>_decimals<span class="token punctuation">)</span> self._balances<span class="token punctuation">[</span>self.msg.sender<span class="token punctuation">]</span> <span class="token operator">=</span> total_supply def on_update<span class="token punctuation">(</span>self<span class="token punctuation">)</span> -<span class="token operator">></span> None: super<span class="token punctuation">(</span><span class="token punctuation">)</span>.on_update<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment"># Tên của token</span> @external<span class="token punctuation">(</span>readonly<span class="token operator">=</span>True<span class="token punctuation">)</span> def name<span class="token punctuation">(</span>self<span class="token punctuation">)</span> -<span class="token operator">></span> str: <span class="token builtin class-name">return</span> <span class="token string">"SampleToken"</span> <span class="token comment"># Ký hiệu của token</span> @external<span class="token punctuation">(</span>readonly<span class="token operator">=</span>True<span class="token punctuation">)</span> def symbol<span class="token punctuation">(</span>self<span class="token punctuation">)</span> -<span class="token operator">></span> str: <span class="token builtin class-name">return</span> <span class="token string">"ST"</span> @external<span class="token punctuation">(</span>readonly<span class="token operator">=</span>True<span class="token punctuation">)</span> def decimals<span class="token punctuation">(</span>self<span class="token punctuation">)</span> -<span class="token operator">></span> int: <span class="token builtin class-name">return</span> self._decimals.get<span class="token punctuation">(</span><span class="token punctuation">)</span> @external<span class="token punctuation">(</span>readonly<span class="token operator">=</span>True<span class="token punctuation">)</span> def totalSupply<span class="token punctuation">(</span>self<span class="token punctuation">)</span> -<span class="token operator">></span> int: <span class="token builtin class-name">return</span> self._total_supply.get<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment"># truy vấn số dư của địa chỉ</span> @external<span class="token punctuation">(</span>readonly<span class="token operator">=</span>True<span class="token punctuation">)</span> def balanceOf<span class="token punctuation">(</span>self, _owner: Address<span class="token punctuation">)</span> -<span class="token operator">></span> int: <span class="token builtin class-name">return</span> self._balances<span class="token punctuation">[</span>_owner<span class="token punctuation">]</span> @external def transfer<span class="token punctuation">(</span>self, _to: Address, _value: int, _data: bytes <span class="token operator">=</span> None<span class="token punctuation">)</span>: <span class="token keyword">if</span> _data is None: _data <span class="token operator">=</span> b<span class="token string">'None'</span> self._transfer<span class="token punctuation">(</span>self.msg.sender, _to, _value, _data<span class="token punctuation">)</span> <span class="token comment"># Chuyển tokne từ </span><span class="token variable">`</span></span>_from<span class="token variable"><span class="token variable">`</span> sang <span class="token variable">`</span></span>_to<span class="token variable"><span class="token variable">`</span> def _transfer<span class="token punctuation">(</span>self, _from: Address, _to: Address, _value: int, _data: bytes<span class="token punctuation">)</span>: <span class="token comment"># Nếu giá trị âm hoặc địa chỉ gửi không đủ số dư thì giao dịch sẽ bị revert</span> <span class="token keyword">if</span> _value <span class="token operator"><</span> <span class="token number">0</span>: revert<span class="token punctuation">(</span><span class="token string">"Transferring value cannot be less than zero"</span><span class="token punctuation">)</span> <span class="token keyword">if</span> self._balances<span class="token punctuation">[</span>_from<span class="token punctuation">]</span> <span class="token operator"><</span> _value: revert<span class="token punctuation">(</span><span class="token string">"Out of balance"</span><span class="token punctuation">)</span> self._balances<span class="token punctuation">[</span>_from<span class="token punctuation">]</span> <span class="token operator">=</span> self._balances<span class="token punctuation">[</span>_from<span class="token punctuation">]</span> - _value self._balances<span class="token punctuation">[</span>_to<span class="token punctuation">]</span> <span class="token operator">=</span> self._balances<span class="token punctuation">[</span>_to<span class="token punctuation">]</span> + _value <span class="token comment"># Nếu địa chỉ đích là 1 contract thì sẽ gọi đến hàm tokenFallback</span> <span class="token keyword">if</span> _to.is_contract: recipient_score <span class="token operator">=</span> self.create_interface_score<span class="token punctuation">(</span>_to, TokenFallbackInterface<span class="token punctuation">)</span> recipient_score.tokenFallback<span class="token punctuation">(</span>_from, _value, _data<span class="token punctuation">)</span> <span class="token comment"># Emits an event log </span><span class="token variable">`</span></span>Transfer` self.Transfer<span class="token punctuation">(</span>_from, _to, _value, _data<span class="token punctuation">)</span> Logger.debug<span class="token punctuation">(</span>f<span class="token string">'Transfer({_from}, {_to}, {_value}, {_data})'</span>, TAG<span class="token punctuation">)</span> |
Deploy
Contract đã xong xuôi, bây giờ chúng ta cùng tìm hiểu các deploy chúng lên mạng testnet
Yeouido với tools tbears.
B1: Tạo file config deploy
deploy_hello.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token punctuation">{</span> <span class="token property">"uri"</span><span class="token operator">:</span> <span class="token string">"https://bicon.net.solidwallet.io/api/v3"</span><span class="token punctuation">,</span> <span class="token property">"nid"</span><span class="token operator">:</span> <span class="token string">"0x3"</span><span class="token punctuation">,</span> <span class="token property">"keyStore"</span><span class="token operator">:</span> <span class="token null keyword">null</span><span class="token punctuation">,</span> <span class="token property">"from"</span><span class="token operator">:</span> <span class="token string">"ĐỊA CHỈ CỦA BẠN"</span><span class="token punctuation">,</span> <span class="token property">"to"</span><span class="token operator">:</span> <span class="token string">"cx0000000000000000000000000000000000000000"</span><span class="token punctuation">,</span> <span class="token property">"stepLimit"</span><span class="token operator">:</span> <span class="token string">"0x5a000000"</span><span class="token punctuation">,</span> <span class="token property">"deploy"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"contentType"</span><span class="token operator">:</span> <span class="token string">"tbears"</span><span class="token punctuation">,</span> <span class="token property">"mode"</span><span class="token operator">:</span> <span class="token string">"install"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"txresult"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"transfer"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> |
deploy_sample_token.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <span class="token punctuation">{</span> <span class="token property">"uri"</span><span class="token operator">:</span> <span class="token string">"https://bicon.net.solidwallet.io/api/v3"</span><span class="token punctuation">,</span> <span class="token property">"nid"</span><span class="token operator">:</span> <span class="token string">"0x3"</span><span class="token punctuation">,</span> <span class="token property">"keyStore"</span><span class="token operator">:</span> <span class="token null keyword">null</span><span class="token punctuation">,</span> <span class="token property">"from"</span><span class="token operator">:</span> <span class="token string">"ĐỊA CHỈ CỦA BẠN"</span><span class="token punctuation">,</span> <span class="token property">"to"</span><span class="token operator">:</span> <span class="token string">"cx0000000000000000000000000000000000000000"</span><span class="token punctuation">,</span> <span class="token property">"stepLimit"</span><span class="token operator">:</span> <span class="token string">"0x5a000000"</span><span class="token punctuation">,</span> <span class="token property">"deploy"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"contentType"</span><span class="token operator">:</span> <span class="token string">"tbears"</span><span class="token punctuation">,</span> <span class="token property">"mode"</span><span class="token operator">:</span> <span class="token string">"install"</span><span class="token punctuation">,</span> <span class="token property">"scoreParams"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"_decimals"</span><span class="token operator">:</span> <span class="token string">"0x12"</span><span class="token punctuation">,</span> <span class="token property">"_initialSupply"</span><span class="token operator">:</span> <span class="token string">"0x3e8"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"txresult"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"transfer"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Hàm on_install
trong contract SampleToken
cần truyền 2 đối số để _decimals
và _initialSupply
để thực thi.
B2: Tạo ví
Chúng ta cài đặt extension ICONex (ví giống như Metamask) để tạo địa chỉ trên mạng ICON. Với trình duyệt Chrome, các bạn có thể tại tại đây
Ấn vào phần tạo ví mới, các bạn sẽ tải file keystore và về đổi đuôi thành file json, chẳng hạn như keystore.json
.
B3: Deploy lên testnet vơi tbears
Thư mục hiện tại chúng ta có
1 2 3 4 5 6 | /hello /sample-token deploy-hello.json deploy_sample_token.json keystore.json |
Trước khi deploy chúng ta cần faucet ICX cho tài khoản trên testnet tại
1 2 3 | tbears deploy hello -k keystore.json -c deploy-hello.json tbears deploy sample-token -k keystore.json -c deploy-sample_token.json |
Transaction hash sẽ được trả về sau khi deploy, chúng ta có thể kiểm tra giao dịch có thành công hay không cũng như địa chỉ của contract trên trang bicon.tracker.solidwallet.io
4. ICON SDK (Javascript SDK)
Mỗi node ICON đều cung cấp các API JSON-RPC. Để tương tác với một node ICON, chúng ta có thể gửi yêu cầu JSON-RPC thô hoặc sử dụng ICON SDK bằng nhiều ngôn ngữ khác nhau. ICON chính thức hỗ trợ Java, Python, JavaScript và Swift. Trong khuôn khổ bài viết, chúng ta sẽ chỉ tìm hiểu qua về 1 loại SDK đó là Javascript SDK.
Cài đặt
Javascript SDK được tích hợp trong 1 package node.js, giúp chúng ta dễ dàng cài đặt và sử dụng
Cài đặt qua npm
1 2 | <span class="token function">npm</span> <span class="token function">install</span> --save icon-sdk-js |
Hoặc link CDN
1 2 | <span class="token operator"><</span>script src<span class="token operator">=</span><span class="token string">"https://cdn.jsdelivr.net/gh/icon-project/<a href="/cdn-cgi/l/email-protection" class="__cf_email__">[email protected]</a>/build/icon-sdk-js.web.min.js"</span><span class="token operator">></span><span class="token operator"><</span><span class="token operator">/</span>script<span class="token operator">></span> |
Dùng SDK tương tác với contract đã deploy
Tạo thư mục sdk và tạo biến môi trường
1 2 3 4 | mkdir sdk cd sdk touch .env |
1 2 3 4 5 6 | <span class="token comment"># .env</span> API_ENPOINT<span class="token operator">=</span><span class="token string">'https://bicon.net.solidwallet.io/api/v3'</span> PRIVATE_KEY<span class="token operator">=</span><span class="token string">'PRIVATE KEY ĐỊA CHỈ CỦA BẠN'</span> ADDRESS_CONTRACT_SAMPLE_TOKEN<span class="token operator">=</span><span class="token string">'ĐỊA CHRI CONTRACT SAMPLE TOKEN ĐÃ DEPLOY'</span> OWNER<span class="token operator">=</span><span class="token string">'ĐỊA CHỈ DÙNG ĐỂ DEPLOY'</span> |
Với các hàm readonly, khi gọi không cần phải ký giao dịch gì cả
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | <span class="token comment">// getBalance.js</span> <span class="token keyword">const</span> IconService <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'icon-sdk-js'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> argv <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'yargs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'dotenv'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> HttpProvider<span class="token punctuation">,</span> IconBuilder <span class="token punctuation">}</span> <span class="token operator">=</span> IconService<span class="token punctuation">;</span> <span class="token comment">// Kết nối đến mạng testnet</span> <span class="token keyword">const</span> provider <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HttpProvider</span><span class="token punctuation">(</span>process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">API_ENPOINT</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> iconService <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">IconService</span><span class="token punctuation">(</span>provider<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> CallBuilder <span class="token punctuation">}</span> <span class="token operator">=</span> IconBuilder<span class="token punctuation">;</span> <span class="token keyword">const</span> owner <span class="token operator">=</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">OWNER</span><span class="token punctuation">;</span> <span class="token keyword">const</span> instanceContract <span class="token operator">=</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">ADDRESS_CONTRACT_SAMPLE_TOKEN</span><span class="token punctuation">;</span> <span class="token keyword">let</span> account <span class="token operator">=</span> owner<span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>argv<span class="token punctuation">.</span>address<span class="token punctuation">)</span> <span class="token punctuation">{</span> account <span class="token operator">=</span> argv<span class="token punctuation">.</span>address<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getBalance</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token comment">// class CallBuilder dùng để build thành các transaction object chuyên gọi các hàm read-only</span> <span class="token comment">// https://link.sun-asterisk.vn/FPM4jf </span> <span class="token keyword">const</span> txObj <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CallBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span>owner<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">to</span><span class="token punctuation">(</span>instanceContract<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">method</span><span class="token punctuation">(</span><span class="token string">'balanceOf'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">params</span><span class="token punctuation">(</span><span class="token punctuation">{</span> _owner<span class="token operator">:</span> account<span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">let</span> balance <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">iconService</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span>txObj<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> balance <span class="token operator">=</span> <span class="token function">parseInt</span><span class="token punctuation">(</span>balance<span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">{</span> balance <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> balance<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">{</span> err <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function">getBalance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Với những hàm khác, khi gọi qua SDK chúng ta cần thực hiện thao tác ký
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | <span class="token comment">// transfer.js</span> <span class="token keyword">const</span> IconService <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'icon-sdk-js'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> argv <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'yargs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'dotenv'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> IconWallet<span class="token punctuation">,</span> HttpProvider<span class="token punctuation">,</span> SignedTransaction<span class="token punctuation">,</span> IconBuilder<span class="token punctuation">,</span> IconConverter <span class="token punctuation">}</span> <span class="token operator">=</span> IconService<span class="token punctuation">;</span> <span class="token keyword">const</span> provider <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HttpProvider</span><span class="token punctuation">(</span>process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">API_ENPOINT</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> iconService <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">IconService</span><span class="token punctuation">(</span>provider<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> CallTransactionBuilder <span class="token punctuation">}</span> <span class="token operator">=</span> IconBuilder<span class="token punctuation">;</span> <span class="token comment">// Import private key cảu account vào wallet, dùng cho việc ký giao dịch</span> <span class="token keyword">const</span> wallet <span class="token operator">=</span> IconWallet<span class="token punctuation">.</span><span class="token function">loadPrivateKey</span><span class="token punctuation">(</span>process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">PRIVATE_KEY</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> owner <span class="token operator">=</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">OWNER</span><span class="token punctuation">;</span> <span class="token keyword">const</span> instanceContract <span class="token operator">=</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">ADDRESS_CONTRACT_SAMPLE_TOKEN</span><span class="token punctuation">;</span> <span class="token keyword">const</span> to <span class="token operator">=</span> argv<span class="token punctuation">.</span>to<span class="token punctuation">;</span> <span class="token keyword">const</span> value <span class="token operator">=</span> <span class="token function">parseInt</span><span class="token punctuation">(</span>argv<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">transfer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token comment">// Class CallTransactionBuilder dùng để build các giao dịch gọi đến các hàm thay đổi trạng thái của blockchain</span> <span class="token comment">// Hàm transfer nhận vào 2 params là `_to` và `_value`</span> <span class="token keyword">const</span> txObj <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CallTransactionBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span>owner<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">to</span><span class="token punctuation">(</span>instanceContract<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">stepLimit</span><span class="token punctuation">(</span>IconConverter<span class="token punctuation">.</span><span class="token function">toBigNumber</span><span class="token punctuation">(</span><span class="token string">'2000000'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">nid</span><span class="token punctuation">(</span>IconConverter<span class="token punctuation">.</span><span class="token function">toBigNumber</span><span class="token punctuation">(</span><span class="token string">'3'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">nonce</span><span class="token punctuation">(</span>IconConverter<span class="token punctuation">.</span><span class="token function">toBigNumber</span><span class="token punctuation">(</span><span class="token string">'1'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">version</span><span class="token punctuation">(</span>IconConverter<span class="token punctuation">.</span><span class="token function">toBigNumber</span><span class="token punctuation">(</span><span class="token string">'3'</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">timestamp</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">method</span><span class="token punctuation">(</span><span class="token string">'transfer'</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">params</span><span class="token punctuation">(</span><span class="token punctuation">{</span> _to<span class="token operator">:</span> to<span class="token punctuation">,</span> _value<span class="token operator">:</span> IconConverter<span class="token punctuation">.</span><span class="token function">toHex</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> signedTransaction <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SignedTransaction</span><span class="token punctuation">(</span>txObj<span class="token punctuation">,</span> wallet<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> txHash <span class="token operator">=</span> <span class="token keyword">await</span> iconService<span class="token punctuation">.</span><span class="token function">sendTransaction</span><span class="token punctuation">(</span>signedTransaction<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">{</span> txHash <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token punctuation">{</span> err <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function">transfer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Chạy:
1 2 3 | node getBalance --address<span class="token operator">=</span><span class="token operator"><</span>tài khoản bạn cần truy vấn số dư token<span class="token operator">></span> node transfer --to<span class="token operator">=</span><span class="token operator"><</span>địa chỉ nhận token<span class="token operator">></span> --value<span class="token operator">=</span> |
Chú thích: Để tìm hiểu các năng của thể của các module ở trong Javascript SDK, các bạn có thể tham khảo ở trên Github