續前篇:https://noise.cash/post/jgmg36rhn05wx 這次要來寫一個網頁程式來和前一篇發布的合約進行互動,這裡假設看的人已經對HTML和JavaScript有一定的了解,所以只會談論連結MetaMask帳戶、和合約互動的程式碼的部份 首先先實際操作一下完成的網頁:https://vcckvv.github.io/SmartContract/HelloWorld/ 沒有MetaMask錢包的人要先安裝MetaMask錢包瀏覽器外掛,因為這個網頁是預設和MetaMask進行連結 第一次連進去應該會要求帳戶的連線,由於這個程式沒有寫切換到goerli測試鏈的功能,所以記得要手動切換到goerli測試鏈上,另外如果沒goerli的幣的話,可以先去水龍頭網站領取:https://goerlifaucet.com/ 按下getValue的按鈕會執行合約中的get()函數,也就是取得合約中value的資料,然後顯示在左邊的輸入框上 按下setValue的按鈕則會執行合約中的set()函數,會把左邊的輸入框中的文字當作輸入參數來執行,按下後會跳出MetaMask的交易確認,接著網頁會等到交易上鏈後再自動執行get()函數,由此顯示出我們的set()函數操作有正確改變合約中value的資料 值得注意的是,如果有多個人在同時間測試的話,value會被設定成最後一個人修改的資料,這個時候就要注意一下合約的交易情況: https://goerli.etherscan.io/address/0x8abb77ff22f8966729603bd49c5c049c4294efd5 接下來看一下完整網頁程式: https://github.com/vcckvv/SmartContract/blob/gh-pages/HelloWorld/index.html ---------------------------------------------------- <html> <head> <title>Hello World</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <input id="showValue" readonly></input><button onclick="onGetValueBtn()">getValue</button><br> <input id="newValue" ></input><button onclick="onSetValueBtn()">setValue</button> </body> <script src="https://cdn.ethers.io/lib/ethers-5.1.umd.min.js"></script> <script> // The Contract interface const abi = [{"constant": false,"inputs": [{"name": "v","type": "string"}],"name": "set","outputs": [],"payable": false,"stateMutability": "nonpayable","type": "function"},{"constant": true,"inputs": [],"name": "get","outputs": [{"name": "","type": "string"}],"payable": false,"stateMutability": "view","type": "function"},{"inputs": [],"payable": false,"stateMutability": "nonpayable","type": "constructor"}]; const contractAddress = "0x8abb77ff22f8966729603bd49c5c049c4294efd5"; let address = null; let provider = null; let contract = null; let contractWithSigner = null; async function init(){ try{ let response = await window.ethereum.request({method: 'eth_requestAccounts'}); address = response[0]; provider = new ethers.providers.Web3Provider(window.ethereum); contract = new ethers.Contract(contractAddress, abi, provider); contractWithSigner = contract.connect(provider.getSigner() ); }catch(err){ alert(err.message); } } init(); async function onGetValueBtn(){ try{ let currentValue = await contract.get(); document.querySelector('#showValue').value=currentValue; }catch(err){ alert(err.message); } } async function onSetValueBtn(){ try{ let newValue=document.querySelector('#newValue').value; let tx = await contractWithSigner.set(newValue); alert(tx.hash); document.querySelector('#showValue').value=""; await tx.wait(); onGetValueBtn(); }catch(err){ if(err.code==4001){//reject alert("User rejected tx."); } else{ alert(err.message); } } } </script> </html> ---------------------------------------------------- (噪音顯示程式碼的空白縮排會有問題,所以上面的程式碼是用全形空白去顯示縮排,要複製程式碼請去網頁裡複製) ---------------------------------------------------- 由於MetaMask沒辦法在打開本機上的HTML檔時開啟功能,所以在測試的時候要放到伺服器上來進行測試,我一般都是在自己電腦上建立一台網頁伺服器,然後放在上面進行測試比較方便,使用的軟體是Http File Server:https://www.rejetto.com/hfs/ ---------------------------------------------------- 這次使用的函數庫是ethers.js,個人的使用經驗上感覺非常便利,這裡只需要簡單地引用這個js檔就能使用: <script src="https://cdn.ethers.io/lib/ethers-5.1.umd.min.js"></script> 注意因為噪音會自動把網址前面的https://去掉,所以我把程式碼中的網址的冒號: 都換成全形的冒號: ---------------------------------------------------- const abi = [{"constant": false,"inputs": [{"name": "v","type": "string"}],"name": "set","outputs": [],"payable": false,"stateMutability": "nonpayable","type": "function"},{"constant": true,"inputs": [],"name": "get","outputs": [{"name": "","type": "string"}],"payable": false,"stateMutability": "view","type": "function"},{"inputs": [],"payable": false,"stateMutability": "nonpayable","type": "constructor"}]; 這串abi代表合約的函數介面資料,之前在Remix進行編譯時(Compile HelloWorld.sol),編譯完介面底下會出現一個ABI的按鈕,按下去就會把產生的ABI資料複製起來,然後就可以貼到程式碼這邊 要注意之後在處理多個contract的情況時,要在上面的CONTRACT下拉表中選對發布的contract,才能得到正確的ABI ---------------------------------------------------- let response = await window.ethereum.request({method: 'eth_requestAccounts'}); address = response[0]; provider = new ethers.providers.Web3Provider(window.ethereum); contract = new ethers.Contract(contractAddress, abi, provider); contractWithSigner = contract.connect(provider.getSigner() ); 這一段就是進行MetaMask的帳戶連結,然後產生provider物件,provider物件基本功能應該是和RPC Server相連線,由此和合約進行互動 RPC Server的網址就是MetaMask設定的區塊鏈的資料中的RPC URL,如果不是商業用的RPC Server也許會有些流量限制,不過測試的時候應該不用考慮那麼多,直接用預設的免費RPC Server就好 產生provider物件之後再產生contract和contractWithSigner物件,這兩個後面和合約互動時會用到 ---------------------------------------------------- let currentValue = await contract.get(); document.querySelector('#showValue').value=currentValue; 要執行合約中讀取性質的函數的方法很簡單,像是我們要執行合約中的get(),就只需要寫成contract.get()就可以了,要注意這個動作會動用到網路,所以是非同步函數,因此要用await去等待值回傳回來 而在JavaScript使用到await的話,函數就要加上async,代表這個函數裡面有非同步的指令,而我們這裡的函數都有用到,所以都有加上async ---------------------------------------------------- let newValue=document.querySelector('#newValue').value; let tx = await contractWithSigner.set(newValue); alert(tx.hash); document.querySelector('#showValue').value=""; await tx.wait(); onGetValueBtn(); 而要執行合約中寫入性質的函數的方法也很簡單,像是我們要執行合約中的set(),就只需要寫成contractWithSigner.set()然後再填入輸入的參數就可以了 執行這個函數後回傳的是交易資料tx,我們可以用await tx.wait()來等待交易上鏈完成,然後繼續其他的動作,這裡是執行onGetValueBtn()用來確定我們的值有真的在鏈上被修改掉 值得一提的是,如果在MetaMask中把pending的交易啟用加速功能(需要多給費用),那麼即使交易上鏈完成,這裡的tx.wait()也沒辦法回傳繼續行動,這個也不能說算是MetaMask的bug,因為本質上算是換成不同的交易 ---------------------------------------------------- 和合約互動的基本功能這樣就完成了,不過還是有些東西沒有提到,像是切換區塊鏈、偵測帳號切換、取得帳號餘額,這些之後會再加進來講解,這裡只寫一些最基本的功能 下一篇要來解說怎麼製作自己的ERC20代幣,之後還會弄個水龍頭網站,敬請期待~
Log in to join in Reading is open to everyone. Replying needs an account.
8 comments
ERC20的水龍頭,手續費高的時候會不會發到破產阿XD
不用擔心,因為我做的水龍頭是要你自己花gas費去鑄造新幣XD
了解XDD
再來支持一下 剛好最近也想做個區塊鏈網站XDD
不錯喔,大大加油!期待之後的成果~
太厲害了=_= 我覺得我這假日要來研究了 可以另外請問完全無經驗寫程式 要寫 安卓app 好入門嗎
如果是要打好程式基礎的話是要從C/C++開始練會比較好 不過考慮到大大完全無經驗,要輕鬆入門的話可以先從HTML/JavaScript開始入門,也不用下載什麼開發工具,直接寫網頁檔,然後用瀏覽器就能跑出結果 安卓app之前我有寫過用Java開發的,Java寫起來很像C++,之前安卓官方換成推薦用Kotlin開發,內容有不少其他程式語言的東西,直接學會遇到很多對新手比較難懂的概念 當然也不用急著學會,慢慢學的話基本上從哪裡入門應該都是沒問題的
了解我再研究看看