所有文章

Web3 全端工程師的技術養成之路 - Day 11 - Web3 與後端:簽名與發送交易

Web3 全端工程師的技術養成之路 - Day 11 - Web3 與後端:簽名與發送交易

完成在後端產生錢包助記詞、私鑰、讀取代幣餘額的實作,今天就會來實作簽名並發送交易的功能,才能完成在區塊鏈上的寫入,作為 Web3 與後端第一部分的結尾。為了產生完整的交易,除了 from address, to address, value 之外,還有像是 nonce, gas price, gas limit, chain ID 等等元素是不可或缺的,在前端的部分沒有講到是因為 wagmi 與 Metamask 已經幫我們處理好這些資料的計算,而在後端這些數值就需要自己算出來。 Nonce 的概念是對於一個固定的錢包地址來說,他發送的第一個交易 Nonce 就必須為 0,第二個 Nonce 為 1 以此類推,因此 Nonce 是嚴格遞增且不能被重複使用的。這個機制也是為了避免 replay attack。想像一下如果 A 簽名了一個轉移 1 ETH 給 B 的交易並廣播出去,如果這個交易的簽章還能重複使用的話,B 就能再廣播一次這個交易讓 A 多轉 1 ETH 給他。有的 Nonce 機制就可以確保 A 要送出的下一個交易的簽名一定跟之前交易的簽名不一樣(因為 Nonce 不一樣就會讓整個交易 hash 出來的結果不一樣) 在以太坊上執行任何交易、智能合約操作時,都需要支付一定的費用,這個費用被稱為 Gas Fee。在發送交易時,他是由 Gas Price 及 Gas 數量這兩個數值相乘算出來的。 在以太坊上進行任何操作時,這些操作其實是由底層的 EVM code 所組成,這是以太坊中類似組合語言的存在。而每個操作都有他對應的 Gas 數量作為這個操作的費用,例如 ADD 指令(加法)花費 3 個 gas、MUL 指令(乘法)花費 5 個 gas。而一筆交易中會執行到的所有指令的 Gas 總合就是這筆交易需花費的 Gas 數量。例如一筆簡單的轉帳交易需要的 Gas 數量通常是 21000,複雜的智能合約操作就需要更多的 Gas。 Gas Price 指的是你願意為每單位的 Gas 支付多少金額,通常以 Gwei 來表示(Wei 是 ETH 的最小單位也就是 10^-18 ETH,因此 10^9 Wei = 1 Gwei ,10^9 Gwei = 1 ETH)。交易指定的 Gas Price 越高,交易確認的速度通常也越快,因為礦工更願意優先確認這筆交易以獲得更高的獎勵。 因此在發送交易時我們需要指定 Gas Limit 跟 Gas Price,Gas Limit 指的就是這筆交易最多只能使用多少個 Gas 單位,因此這樣就能算出一筆交易最多會花多少手續費。例如假設進行一個 Swap 交易要花 80,000 個 Gas,而當下以太坊的 Gas Price 為 20 Gwei,那就可以計算出這筆交易的手續費會是 80000 * 20 * 10^-9 = 0.0016 ETH ,再乘上當下 ETH 的價格 1629 USD 就可以算出大約要花 2.61 USD 的手續費。 若設定的 Gas Limit 太低,交易可能因為沒有足夠的 Gas 而失敗,但還是需要支付已經消耗的 Gas 費用(交易會上鏈但在 Etherscan 上會顯示交易失敗,而且 Gas Fee 照扣)。若 Gas Price 設定的太高可能會花不必要的錢,但太低又可能會讓交易要等很久才上鏈,因此正確設定 Gas 的參數非常重要。 在 ethclient 物件中可以使用SuggestGasPrice方法來查詢當前的 Gas Price,以及 EstimateGas 方法可以估算這筆交易大約會花多少 Gas,而有時為了確保交易成功會再基於這個值往上加一些 Gas。 當我們說一條鏈是 EVM 相容時(例如以太坊主網、Sepolia 測試網、Polygon、Arbitrum 等鏈),代表像私鑰格式、地址、交易簽名方式、智能合約的程式碼等等執行層的機制都是跟以太坊幾乎一樣的(差異可能較多是在共識層也就是節點之間如何達成共識、挖礦機制等等),一個很大的好處是開發者可以在不同的鏈上都部署相同的智能合約,而不需要做任何修改,甚至部署的合約地址在各條 EVM 相容的鏈都可以一模一樣。 但為了確保交易的安全性(避免 replay attack),每條 EVM 相容的鏈需要有自己獨特的 Chain ID,才能用來在交易中區分不同的 EVM 鏈。而 Chain ID 的概念是在 EIP-155 中定義的,他讓交易的簽名計算中多包含了 Chain ID,這樣即使交易在以太坊主網上有效,它也不能被重放到其他鏈上,因為每個鏈的 Chain ID 都是獨特的。 chainlist 是一個知名的網站,上面列出了許多 EVM 相容的鏈,並提供了他們的節點 JSON-RPC 網址、Chain ID、區塊鏈瀏覽器(Explorer)連結等資訊。對於要新增 EVM 相容鏈到錢包 Extension 時是個很有用的工具。在裡面搜尋 Sepolia 並勾選 Include Testnets 就可以看到他對應的 Chain ID 是 11155111。
繼續閱讀
Web3 全端工程師的技術養成之路 - Day 10 - Web3 與後端:建立錢包與取得 Token Balance

Web3 全端工程師的技術養成之路 - Day 10 - Web3 與後端:建立錢包與取得 Token Balance

實作完錢包登入的雛形,這個錢包在使用者的瀏覽器 Extension 內管理的。而有些時候也會需要在後端管理錢包,例如當使用者要把幣打到中心化交易所的入金地址時,交易所會產生一個錢包地址給使用者,並保管好這個錢包的私鑰,使用者入金完成後再自動把這個錢包內的幣轉到歸集錢包中(這樣就能統一把使用者的資金放在幾個大錢包中)。 因此今天我們會來實作產生助記詞、私鑰及錢包地址的功能。有了地址後就能取得他在鏈上的代幣餘額、持有的 NFT 數量等資訊,這樣才能基於這些資訊來自動發送轉出代幣的交易。不過今天我們會先專注在讀取資料的階段,明天才會進到發送交易的實作。 這邊先只考慮 12 個字的註記詞(12 ~ 24 個字都有可能)。這個格式就是 BIP-39 標準定義的,寫清楚了要用哪些英文單字以及為何選擇這些字等等。在 BIP-39 中總共有 2048 個英文單字,也就是 2 的 11 次方,代表一個單字內會有 11 bits 的資訊量,而 12 個字加起來總共就有 132 bits,這樣就剛好可以對應到一個 128 bits 的隨機數(剩下的 4 個 bits 是會是前 128 bits 的 checksum 來提高容錯率)。這個 128 bits 的隨機數就是能用來產生大量錢包私鑰的根源,也被稱為 seed (因此註記詞又被稱為 seed phrase) 有了這個 128 bits 的隨機數後,接下來就可以透過 BIP-32 標準定義的演算法從他衍生出大量的錢包。他會先從 seed 算出一個 master key (對應到下圖中的 Master Node),接下來就可以產生一整個樹狀結構的錢包們,每個點都是一個錢包(因此有對應的公私鑰)。所以當沿著這棵樹往右邊走的時候,選擇不同的路徑(分支)就會產生不同的錢包,而且他的特點是只要 seed 跟路徑參數是固定的,就會產生確定的錢包公私鑰,所以這個標準才被稱為 Hierarchical Deterministic Wallet(階層式確定性錢包),簡稱 HD Wallet。至於路徑參數會是長得像 m/0/1/1 的字串,代表每一步往右走時選擇的分支是什麼。 但是一個 seed 可以產生太多的錢包公私鑰了,對以太坊來說要怎麼知道一個註記詞預設產生的錢包是哪個呢?這就是 BIP-44 定義的內容了。它規定如果要從 seed 產生預設的比特幣錢包,就要使用 m/44'/0'/0'/0/0 這個路徑參數。而如果要產生預設的以太坊錢包,就要使用 m/44'/60'/0'/0/0 ,他們的差別在路徑的第二個數字不同,這就是 BIP-44 中定義不同的鏈必須要用他對應的數字來產生錢包(定義列表)。 有了第一個錢包後,第二個錢包就只要對路徑的最後一個數字 +1 就能從 seed 算出來了,後續的錢包就可以以此類推。另外在路徑上有個 ' 代表這是 hardened derivation,是個提高安全性的機制,有興趣的讀者可以再深入研究。 了解以上概念後就能理解接下來的程式碼。以下會使用 go-bip39 套件來產生註記詞,以及 go-ethereum-hdwallet 套件來產生這個註記詞對應的兩個預設錢包。直接來看實作
繼續閱讀
Web3 全端工程師的技術養成之路 - Day 8 - 智能合約基礎

Web3 全端工程師的技術養成之路 - Day 8 - 智能合約基礎

智能合約的定義其實很單純,如同 Ethereum 官方文件描述的: A “smart contract” is simply a program that runs on the Ethereum blockchain. It’s a collection of code (its functions) and data (its state) that resides at a specific address on the Ethereum blockchain. 所以其實嚴格來說他不是合約也沒那麼智能,Vitalik (以太坊的創始人)就提過應該要把它取名為 Persistent Scripts,不過既然已經廣為流傳,大家還是習慣叫他智能合約。以下是一個由 Solidity 寫的最簡單的智能合約,可以做到用 set 把一個資料存在這個合約上,並用 get 拿到這個資料。 最廣為人知的智能合約開發語言就是 Solidity,他的寫法類似 Javascript 所以還算好上手。除了 Solidity 外也還也不少其他語言: Vyper: 可以用類似 Python 的語法來寫智能合約,他的語法比較高階因此也蠻多人喜歡,按照 DeFi TVL 的統計數據目前是第二名(僅次於 Solidity)的語言。 Yul: 寫法比較像組合語言,在 Solidity 中有時需要做底層的 gas fee 優化時會使用 inline assembly 的方式,Yul 就可以跟 Solidity 很好的結合 Huff: 近期開始有不少討論度的底層語言,宣稱如果精通 EVM 的話可以寫出比 Yul 更省 gas fee 的合約。 更多關於這些語言的比較可參考:Solidity vs. Vyper: Which Smart Contract Language Is Right for Me? 再來是開發框架的簡介,以下幾個都是開發 Solidity 可以使用的框架: Remix:較老牌的基於瀏覽器的 IDE,適合在雲端上快速實作原型。 Truffle:流行的開發框架,有內建的智能合約編譯、部署、測試的工具。 Hardhat:較新也比 Truffle 靈活的框架,更易於用來寫測試及 debug,像是有內建在合約中執行 console log 的 debug 方式。 Foundry:更新也比 Hardhat 更快的開發框架,提供純用 Solidity 寫的測試方式(相較於 Truffle Hardhat 都是用 Javascript 寫測試),許多人已經從 hardhat 換成使用 foundry。 關於這四個開發框架實際應用的方式,可以參考 Remix vs Truffle vs Hardhat vs Foundry。我個人學習的開發框架主要是 Hardhat 跟 Foundry,因為我比較喜歡學習新的框架跟體驗它的好處,讀者可以挑有興趣的框架學習,網路上都有大量相關的資源,或是從官方文件一個一個爬文就是很好的起點。 在智能合約中除了變數與方法,還有一個概念沒有介紹到,也就是 Event。例如 transferFrom() 方法的最後一行其實會發出一個像這樣的 event: Transfer(_from, _to, sendAmount) ,在智能合約裡可以找到他的定義: 而 Transfer 也是 ERC-20 標準中定義的 Event。Event 可以用來方便查詢關於一個智能合約的歷史交易中,大家感興趣的事件。像當我想列出我的地址過去所有 USDT 的轉帳歷史時,如果要一個一個查詢我過去有跟 USDT 合約互動的紀錄會很麻煩,而且這還沒考慮到別人用 transferFrom() 把我 USDT 轉走的情況,就變成要看完所有跟 USDT 合約互動的交易才不會遺漏,而現在這些交易已經高達 1.7 億筆! 有了 Event 的機制,當 USDT 合約中有發生任何 Token Transfer 都發出 Transfer event 的話,等於是讓以太坊節點幫我們做 indexing,讓任何人可以直接 filter 出這個合約中特定內容的 event 有哪些。例如我想知道從我地址轉入或轉出 USDT 的所有記錄,就只要 filter 出 USDT 合約上 from 或是 to 的值等於我的地址的 Transfer Event 就可以了。後續會在後端的內容中介紹如何拿到 Token Transfer 的資料。 在 Etherscan USDT 介面上的 Events Tab 可以看到近期這個智能合約發出的 Events,以及每筆交易的 Logs Tab 可以看到該筆交易觸發了哪些智能合約中的哪些 Event(例如上次轉出 UNI token 的交易 Logs)。 FT vs NFT 介紹完了 ERC-20 Token 接下來就能介紹更多的代幣標準,包含 ERC-721 及 ERC-1155。這裡就要講到 Fungible Token(FT) 跟 Non-Fungible Token(NFT) 之間的差別。 Fungible Token 又稱同質性代幣,前面介紹的 ERC-20 Token 就是屬於 Fungible Token,因為每一單位的 USDT 都是一樣的,如果 A 跟 B 都有 1 USDT,A 把他的 1 USDT 轉給 B,B 就會有兩個 USDT,代表 A 身上的 USDT 跟 B 身上的 USDT 是同質、沒有差異的。Fungible Token 的特性就是可以任意合併或拆分,適合用來實作貨幣的智能合約。 與之相對的就是 Non-Fungible Tokens,又稱非同質性代幣,代表每個 Token 都是獨一無二、不同質的。例如知名的 Bored Ape Yacht Club (BAYC) NFT 就是由一萬張 Ape 的圖片組成,每個 Ape 都有他對應的 ID、圖片、特色,因此就算我有兩個 BAYC NFT 他們也無法合併,而是兩個分開的 Token 並且可以各自被交易、轉移。NFT 也是無法分割的,沒辦法像 FT 一樣轉出 0.5 個 NFT。最知名的 NFT 標準包含 ERC-721 與 ERC-1155,常被用來實作像數位收藏品、遊戲道具、抽獎券等等可以對應到現實世界中「物品」或「資產」的概念。科普的介紹推薦看 老高關於 NFT 的介紹影片。 至於 ERC-721 跟 ERC-1155 有怎樣的差別,簡單來說 ERC-721 代表的是每個 Token 都是獨一無二的 NFT,如數位藝術品每一件都是獨一無二的。ERC-1155 則是代表有部分 Token 是一樣的 NFT,例如遊戲中可能會有不同種類的藥水,但每種藥水本身是同質的沒有任何差異。背後的技術細節可以參考 ERC-721 及 ERC-1155 的介面定義,可以更了解這兩個標準的合約支援的操作。
繼續閱讀
ERC404 合約程式碼導讀

ERC404 合約程式碼導讀

ERC404是近期非常紅的提案,主打圖幣結合,也就是一個合約同時擁有ERC20及ERC721的特性,並擁有以下特徵: * 持有一個 NFT就代表你也持有一顆 ERC20,持有一顆 ERC20 就代表你也持有一顆NFT。 重新鑄造一個 NFT,發送方會減少一顆 ERC20 及燒毀一個 NFT。(燒毀的NFT會是狀態變數陣列中最後一個tokenId) 交易/轉移一個NFT,接收方會增加一顆ERC20及收到該NFT,發送方會減少一顆 ERC20 及發送的 NFT。 交易/轉移一顆 ERC20,接收方會增加一顆ERC20及重新鑄造一個NFT,發送方會減少一顆ERC20及燒毀一個NFT。(燒毀的NFT會是狀態變數陣列中最後一個tokenId) 上述特性,讓 NFT 碎片化,並可以不斷的交易 ERC20 來重新鑄造新的 NFT,讓 NFT 出現不喜歡就可以刷掉重新鑄造的可能。 Pandora則是該提案合約的第一個項目,地址見下方連結: https://etherscan.io/token/0x9e9fbde7c7a83c43913bddc8779158f1368f0413?a=2656#code
byPaul Wu-2024-04-04
繼續閱讀
Web3 全端工程師的技術養成之路 - Day 7 - Web3 與前端:實作錢包登入 Part 1

Web3 全端工程師的技術養成之路 - Day 7 - Web3 與前端:實作錢包登入 Part 1

錢包登入的實作。很多 DApp 如 Blur(NFT marketplace)、Lenster(Web3 社群平台)都是使用錢包地址作為唯一識別使用者的 ID,這樣的好處是在 Web3 的世界就不需依賴任何 Web2 世界的登入方式(Google, Facebook 等等),是個純去中心化的登入方式,而且只有知道私鑰的人才能掌握這個錢包並登入。而這個登入機制由於涉及簽名的概念跟前後端的實作,今天會先帶大家了解以太坊簽名的幾種類型與機制,再講到前端需要提供怎樣的資料給後端,最後介紹 Sign in with Ethereum 這個登入的標準。 而我要怎麼從一個帳戶(地址)轉帳出去,就必須證明我擁有這個地址的使用權,這就是透過這個地址背後對應的一把「私鑰」,透過私鑰與一系列密碼學的計算產生「簽章」後廣播給全世界的人,別人就可以透過這個「簽章」來驗證這筆交易是否真的是由擁有私鑰的人簽名出來的。如果驗證通過,這筆轉帳的交易才會成立並被包含到區塊鏈的帳本中 詳細介紹以太坊中 Sign Personal Message 跟 Sign Typed Data 的概念,並使用 Sign Personal Message 來實作錢包登入的前端部分,拿到 Signature 以便未來傳給後端做驗證。最後介紹並實作了 Sign in with Ethereum 標準來統一錢包登入的訊息規格。Sign in with Ethereum 官方文件已經有很完整的各語言的實作,有興趣的讀者可以往下研究。以及像 Rainbow Kit 中也有 Authentication 模組,是使用 Next Auth 來實作 SIWE 登入,都是很好的資源。
繼續閱讀
Web3 全端工程師的技術養成之路 - Day 6 - Web3 與前端:RainbowKit + Wallet Connect

Web3 全端工程師的技術養成之路 - Day 6 - Web3 與前端:RainbowKit + Wallet Connect

Rainbow Kit 就是可以用來快速開發一個好看的連接錢包功能的 library,包含多種錢包連接選項、更改主題顏色等等,從這裡也會延伸介紹他支援的 WalletConnect 協議,並實際串上 WalletConnect 協議來發送交易。 RainbowKit 是由 Rainbow 錢包開發的 Web SDK,許多 DApp 都有使用,主要是因為他的 UI/UX 做得很好,整合上也很容易。要看呈現效果的話可以在他的官網右上角點擊 Connect Wallet 看到連接錢包的列表
繼續閱讀
Web3 全端工程師的技術養成之路 - Day 5 - Web3 與前端:幫 DApp 加功能

Web3 全端工程師的技術養成之路 - Day 5 - Web3 與前端:幫 DApp 加功能

UNI 幣本質上背後就是一個智能合約,可以先把智能合約理解成跑在區塊鏈上的程式。只是 UNI Token 的智能合約符合 ERC20 標準,這個標準是最廣泛被應用來實作代幣的標準(像以太坊上常見的 USDT, USDC, DAI, UNI 都是) totalSupply() 代表這個代幣的總發行量, balanceOf(account) 可以拿到一個地址的代幣餘額, transfer(to, amount) 可以指定要把我的代幣轉多少給誰。其他 function 今天還不會用到,有興趣的讀者可以先自行研究。 所以只要 UNI 的智能合約實作了這些 function,他就可以被稱為符合 ERC20 標準的智能合約,並且就支援一個代幣所需要的基本功能。讀到這邊大家可能也理解到了在以太坊上只有 ETH 是以太坊的「原生」代幣,其他代幣都是用智能合約實作出來的,透過把各個地址的代幣餘額紀錄在智能合約上,來模擬一個代幣的帳本。有些人會用 Coin 跟 Token 來區分這兩個概念,Coin 指的是這個區塊鏈原生的幣,Token 則指的是在這個鏈上透過智能合約模擬出來的幣,例如可以說 Polygon 這條鏈的 Coin (原生代幣)是 MATIC,而在 Polygon 鏈的 ETH 幣是 Token。 很多代幣的 decimals 會是 18,因為以太坊原生的 ETH 最小單位也是 10^-18 ETH,也被稱為 wei。不過也有蠻多 decimals 是 6 的 token,所以每次都從鏈上查詢是最精準的。這樣就能顯示正確的餘額了!
繼續閱讀
Web3 全端工程師的技術養成之路 - Day 4: Web3 與前端:實作第一個 DApp

Web3 全端工程師的技術養成之路 - Day 4: Web3 與前端:實作第一個 DApp

區塊鏈的本質其實就是一個帳本,紀錄著每個帳戶(也就是地址)上持有多少資產的資訊。比較特別的是這些資訊會被公開並備份到大量的電腦上(我們把它稱為區塊鏈的節點),透過密碼學的機制確保這個帳本是無法竄改的。 當我們想開發一個 DApp 時,如果還要自己架設區塊鏈節點,並且把所有區塊鏈的歷史資料全部同步下來,那勢必會花很高的儲存空間與網路頻寬成本,例如截至今天比特幣的歷史資料已超過 500GB,以太坊則超過 1000GB,而且每個節點要能即時跟其他節點同步資料。因此最簡單的作法是使用別人已經建好的節點服務,而上次介紹的 Alchemy 則是市面上最有名的節點服務提供商之一(另外還有像 Infura、Quicknode 等等),接下來會假設大家已經註冊 Alchemy 服務。另外對自建節點這個主題有興趣的話也可以參考 Ethereum 的 Run a node 教學。 我們會使用 wagmi 這個套件來實作今天需要的功能。wagmi 提供完整的 hooks 可以用來跟錢包、Ethereum 互動,我們就不用自己用更底層的 ethers.js 或 viem 甚至 JSON-RPC 開始寫。安裝方式也很簡單: pnpm i wagmi viem 而因為 wagmi 套件還蠻常改版,有時會造成套件不相容的問題(v1 也是最近才推出),現在我安裝的版本是 viem v1.9.0 以及 wagmi v1.3.10,如果未來看到的介面不同可能是這個原因。 另外有趣的一個小知識是 wagmi 是 We All Gonna Make It 的簡寫,主要是因為 NFT 流行的早期一群早期使用者會很常在 Discord, Twitter 等地方刷 WAGMI 很期待 NFT 項目的前景,就成為了一個 web3 的迷因。
繼續閱讀