Forked from Ankarrr/【Ethereum 智能合約開發筆記】不用自己跑節點,使用 Infura 和 web3.js 呼叫合約.md
Created
July 23, 2020 07:36
-
-
Save balduran/2d78d34ae80aa78d4bab61400f76e3a3 to your computer and use it in GitHub Desktop.
Revisions
-
Ankarrr revised this gist
Jan 26, 2018 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,10 +1,10 @@ # 【Ethereum 智能合約開發筆記】不用自己跑節點,使用 Infura 和 web3.js 呼叫合約  > Infura 提供公開的 Ethereum 主網和測試網路節點。到 [Infura 官網申請](https://infura.io/signup),只要輸入一點基本資料和 Email,就可以收到 API-key。  --- -
Ankarrr created this gist
Jan 26, 2018 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,213 @@ # 【Ethereum 智能合約開發筆記】不用自己跑節點,使用 Infura 和 web3.js 呼叫合約  > Infura 提供公開的 Ethereum 主網和測試網路節點。到 [Infura 官網申請](https://infura.io/signup),只要輸入一點基本資料和 Email,就可以收到 API-key。  --- ## 使用 RPC 查詢合約內儲存的狀態 最常需要查詢的狀態就是 Token 的餘額啦。我就用 EOS 代幣合約最為範例試看看。 ### 取得合約資訊 可以透過 Etherscan,大部分知名的合約可以直接搜尋到。  要呼叫合約,至少需要: - **合約地址**,例如 0x86Fa049857E0209aa7D9e616F7eb3b3B78ECfdb0 - **要呼叫的 function signature**,例如以 ERC 20 代幣合約來說,查詢餘額要呼叫的 function 是 `balanceOf(address)`,其對應的 function signature 是 `70a08231`。 如何取得 function signature 呢?以 `balanceOf(address)` 為例: 1. 把 `balanceOf(address)` 經過 sha3 0x70a08231b98ef4ca268c9cc3f6b4590e4bfec28280db06bb5d45e689f2a360be 2. 取除了 `0x` 外,前面的 8 位 70a08231 以上流程可以用任何工具完成,以 web3.js 為例: var functionSig = we3.sha3("balanceOf(address)").substr(2,8) 另外也可以把 contract code 貼到 remix。在合約的 Details 中可以看到完整的合約介面和對應的 function signature。  ### 使用 RPC 可以透過一個簡單的 POST 用 Infura 提供的節點呼叫一個 RPC。有哪些 RPC method 可以看 [Ethereum RPC doc](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sendtransaction)。 如果要呼叫的 function 只是查詢,而沒有要更新合約的狀態,那就用 `eth_call` 這個 RPC。POST Data 如下: { "jsonrpc":"2.0", "method":"eth_call", "params":[ { "to":"0x86Fa049857E0209aa7D9e616F7eb3b3B78ECfdb0", "data":"0x70a0823100000000000000000000000033b8287511ac7F003902e83D642Be4603afCd876" }, "latest" ], "id":123 } 其中 `params` 的值包含: - `"to"`:合約地址 - `"data"`:丟給合約的參數。由三個部分組成:`0x`、`70a08231`和一個 32 bytes 的參數 `00000000000000000000000033b8287511ac7F003902e83D642Be46`(也就是我要查詢的帳戶) - `"latest"`,代表使用最新的區塊鏈資料 #### 範例 // Request curl https://mainnet.infura.io/<your-api-key> -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0x86Fa049857E0209aa7D9e616F7eb3b3B78ECfdb0", "data":"0x70a0823100000000000000000000000033b8287511ac7F003902e83D642Be4603afCd876"}, "latest"],"id":123 }' // Result { "jsonrpc": "2.0", "id": 123, "result": "0x000000000000000000000000000000000000000000000000b1d16ec625a59d3e" } `0x000000000000000000000000000000000000000000000000b1d16ec625a59d3e` 是十六進位,換算成十進位是 `12813144212159962430`。也就是小弟只有少少的 **12.x** 個 EOS token。 --- ## web3.js(JavaScript API) 如果要更新合約的狀態,就需要送 transaction,要送 transaction 就需要錢包或是說 private key 來 sign transaction 和提供 Ether 做手續費。因為送 transaction 要手續費,為了省點錢,我就部一個合約在 **Ropsten 測試鏈**上做這次的試驗。以上步驟比較麻煩,**我就用 web3.js 寫兩個簡單的程式,一個查詢合約狀態、一個更新合約狀態**。web3.js 的功能和 RPC 差不多,但是個 JavaScript 套件。有哪些 API 可以用請看 [JavaScript API doc](https://github.com/ethereum/wiki/wiki/JavaScript-API#web3versionapi)。 ### 安裝 npm install web3, ethereumjs-tx ### 官方建議的初始化方式 var Web3 = require('web3'); if (typeof web3 !== 'undefined') { web3 = new Web3(web3.currentProvider); } else { // set the provider you want from Web3.providers web3 = new Web3(new Web3.providers.HttpProvider("https://ropsten.infura.io/<your-api-key>")); } ### 部署測試合約 這次部署一個很簡單的合約。合約只儲存一個狀態 `data`,並可透過 `set()` 更新狀態。 合約程式碼: pragma solidity ^0.4.19; contract SimpleStorage { uint public data; function set(uint x) public { data = x; } } 合約地址:`0x5fb30123b9efedcd15094266948fb7c862279ee1` 合約的 function signatures: { "73d4a13a": "data()", "60fe47b1": "set(uint256)" } --- ### 查詢合約狀態 使用 `web3.eth.call`。 // Request var result = web3.eth.call({ to: "0x5fb30123b9efedcd15094266948fb7c862279ee1", data: "0x" + "73d4a13a" }); // Print Result console.log(parseInt(result, 16)); Print 出來結果會是 `0`,因為還沒更新過狀態。 --- ### 更新合約狀態 使用 `web3.eth.sendRawTransaction`。 > RPC 和 web3.js 提供的 `SendTransaction` 都是連到一節點,使用節點中的帳戶發送 transaction。而如果要用自己的帳戶就要用 `sendRawTransaction`,也就是說要自己建立 transaction、自己 sign 過,再透過 `sendRawTransaction` 發送。 #### Define raw transaction var rawTx = { nonce: '0x14', gasPrice: '0x3B9ACA00', gasLimit: '0xC20A', to: '0x5fb30123b9efedcd15094266948fb7c862279ee1', value: '0x00', data: '0x' + '60fe47b1' + '000000000000000000000000000000000000000000000000000000000000000a' } `rawTx` 中包含: - `nonce`:紀錄目前帳戶送出的交易數,用來避免 replay attack,每次送要加 1。可以用 RPC `eth_getTransactionCount` 查詢目前帳戶的 nonce。也可以用 Etherscan 查,但 Etherscan 顯示的 `No Of Transactions` 會包含送出去但沒有成功的交易,所以會不準 - `gasPrice`:一般用 1 Gwei(= 1000000000 = 0x3B9ACA00) - `gasLimit`:gaslimit 估算可參考 [使用ethereum browser計算gas cost](https://medium.com/taipei-ethereum-meetup/%E4%BD%BF%E7%94%A8ethereum-browser%E8%A8%88%E7%AE%97gas-cost-9122950a04f7) - `to`:合約地址 - `value`:要送的 Ether 數量,因為只是要呼叫合約所以設 0 - `data`:丟給合約的參數。由三個部分組成:`0x`、`60fe47b1`和一個 32 bytes 的參數 `000000000000000000000000000000000000000000000000000000000000000a`(我要更新的值,這邊設 10) #### Create and Sign raw transaction 要引入另一個套件 `ethereumjs-tx`。記得先用 npm 安裝。 var Tx = require('ethereumjs-tx'); 建立 raw transaction。 var tx = new Tx(rawTx); 用自己的 private key sign。 const privateKey = new Buffer('<your-private-key>', 'hex') tx.sign(privateKey); #### Send raw transaction var serializedTx = tx.serialize(); web3.eth.sendRawTransaction('0x' + serializedTx.function function function toString() { [native code] }() { [native code] }() { [native code] }('hex'), function(err, hash) { if (!err) { console.log(hash); } else { console.log(err) } }); 成功就會回傳一個 transaction hash,像是: 0x2a9d89b0f329853b5c0f83c83cea4cfa2e38ddd1041d9abd0afcc9af5ed1bf1b 交易成功送出且被收進 block 後,再次查詢合約狀態,Print 出來結果就會是 **10**。 可以透過 Etherscan 確認交易有沒有被收進 block 以及合約執行的結果(可能因為參數錯誤導致執行失敗)。  ## References - [在區塊鏈上建立可更新的智慧合約(一)](https://medium.com/@twedusuck/%E5%9C%A8%E5%8D%80%E5%A1%8A%E9%8F%88%E4%B8%8A%E5%BB%BA%E7%AB%8B%E5%8F%AF%E6%9B%B4%E6%96%B0%E7%9A%84%E6%99%BA%E6%85%A7%E5%90%88%E7%B4%84-cbe015bdb339) - [Ethereum JSON RPC Document](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactioncount) - [We3.js API Document](https://github.com/ethereum/wiki/wiki/JavaScript-API)