3

DApp 開發工具 ethers-token 介紹

 2 years ago
source link: https://medium.com/taipei-ethereum-meetup/dapp-%E9%96%8B%E7%99%BC%E5%B7%A5%E5%85%B7-ethers-token-%E4%BB%8B%E7%B4%B9-aac4d55a5a78
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

DApp 開發工具 ethers-token 介紹

0*VLeW_U8mrw0iJ4mj

Photo by Shubham Dhage on Unsplash

在 Ethereum 上開發 DApp 和智能合約(smart contract,以下簡稱合約)時,常常需要經手各式各樣的 token,並且處理各種與 token 相關的事務,像是單位轉換、包裝、轉移和授權等等。隨著 DeFi 生態持續成長,token 的種類也越來越多樣,除了區塊鏈本身運作所需的 native token (原生代幣,如 ETH)之外,還衍生出許多透過智能合約實作的代幣標準,如 ERC20ERC721 等等。

ethers-token 是一個基於 ethers.js 幫助 DApp 開發者以更直覺、更語意化的方式處理 token 的 JavaScript/TypeScript 工具,目前主要支援了 native token 與 ERC20 token 等 fungible token(同質化代幣)的使用情境,未來不排除持續增加支援的 token 種類,如更多的 fungible token 標準、或是 non-fungible token(NFT,非同質化代幣)的應用情境等等。

讓我們先來了解一下,在沒有 ethers-token 之前,開發與測試 DApp 的模樣。

接下來的內容需要讀者對合約開發和測試有基本的概念,並且對 hardhatethers.js 工具有基本的認識。

沒有 ethers-token 之前

由於筆者大多經驗著重在智能合約開發,因此本文將以「在測試環境中與 UniswapV2 合約進行 token 兌換」為例子,來展示 ethers-token 所帶來的改變。

讓我們先來了解一下接下來例子裡會使用到的 UniswapV2 Router 合約的介面:

UniswapV2 Router 介面

swapExactTokensForTokens 是一個在 UniswapV2 進行 token 兌換的方法,其中 amountIn 代表使用者要拿進來交換的 token 數量,對應的 token 地址會指定在 path[0]amountOutMin 代表使用者希望最少能夠兌換出來的 token 數量,對應的 token 地址會指定在 path[path.length — 1]path 為兌換 token 的路徑;to 為 token 兌換出來後要歸誰所有;deadline 為這筆兌換的期限。

以實際的例子來說,假設今天使用者有 100 DAI,想要在 UniswapV2 進行 DAI -> USDC 的兌換,參數的示意大致如下:

在 UniswapV2 兌換 100 DAI -> USDC 參數示意

在對 UniswapV2 介面有基本的了解後,接下來將會使用 hardhat 和它的 forking network 功能,在本地的測試環境模擬 Ethereum 主網的狀態,以實際的 TypeScript 程式碼與 UniswapV2 進行 token 兌換:

沒有使用 ethers-token 與 UniswapV2 進行 token 兌換的測試

由於 token 本身是合約,在 L25–L26 可以看到,為了使用 token 的功能,必須要先建立 token 合約物件,而受限於 mocha(hardhat 內裝的測試框架)的編排模式,非同步(async/await)初始化行為只能放在 hook 或是測試案例中執行,導致在測試案例之間共用 token 合約時,需要先宣告沒有初始值的可賦值的變數(L19–L20),並主動標示適當的型別(無法享受 TypeScript 賦值時的自動型別推斷),最後在允許非同步行為的 hook 中完成賦值。

上述初始化共用變數的方式,會使得測試集(test suite)裡需要宣告許多與測試目標不相關的變數;而需要主動標示這些沒有初始值的變數型別,會強迫開發者在測試檔案中引入許多不必要的型別進來。

除此之外,在 L30 和 L34–L35 可以看到過往處理 token 數量的方式,由於 token 面額受到其小數位(decimals)的影響,儘管 1 顆 DAI 與 1 顆 USDC 所代表的面額相同,但背後的數字卻是 1 * 10¹⁸ 與 1 * 10⁶ 的差別,在實作 token 兌換邏輯、或是串接外部流動性池時,開發者需要特別留意小數位的轉換。

總的來說,我們通常會使用貨幣的心智模型來理解 token,但實際在 DApp 處理 token 時,卻需要分為鏈上操作(包含轉帳、授權等動作)以及數量匯兌兩個部分來處理,token 概念的分散使得開發者在撰寫程式時需要同時注意不同面向的細節,增加了許多認知上的負擔。

有 ethers-token 之後

ethers-token 旨在以一個概念完整性的單元來表示 token,提供符合貨幣心智模型的介面,讓開發者以更直覺的方式操作 token。

讓我們來看看前一小節的測試案例在使用 ethers-token 改寫後的樣子:

使用 ethers-token 與 UniswapV2 進行 token 兌換的測試

首先,L13–L23 可以看到,ethers-token 能以同步的方式設置好各種 token 的配置,初始化的過程不受限於非同步(async/await)操作,讓開發者能以更靈活的方式編排程式,甚至可以進一步將 token 抽取到獨立的檔案,以常數的方式 export 出去,讓不同的模組及測試共用。

得益於這樣的好處,測試集 before hook 裡可以省略初始化 token 合約的動作,也不需要額外配置儲存 token 合約物件的變數,讓測試變得簡潔與聚焦,讀者可以比對一下兩個例子中 before hook 的差異。

接著,ethers-token 建構出來的 token 建構子(L13-L23),本身能夠以函式呼叫的方式來建立代表特定數量的 token,例如 DAI(100) 即代表 100 顆 DAI,在程式中等價於 100 * 10¹⁸ 的 ethers.BigNumber,並且兼容於各種 ethers.BigNumber 的使用情境,例如 L49-L50 可以看到 token 建構子創建出來代表 token 數量的物件,能夠直接當作參數來呼叫合約的方法。

最後,ethers-token 產生出來的 token 建構子,以及 token 建構子建立代表 token 數量的物件,皆封裝了許多需要鏈上操作的 token 行為,例如 L45 使用了 DAI(100) 身上的 fromapprove 來代表使用者授權 100 顆 DAI 的額度給 UniswapV2;L57 則使用了 USDC 建構子身上的 balanceOf 方法來查詢使用者的 USDC 餘額。

更多詳細的功能介紹請參考 ethers-token README

ethers-token 是一個基於 ethers.js 的 JavaScript/TypeScript 工具,透過一個概念完整性的單元來表示 token,提供符合貨幣心智模型的介面,幫助 DApp 開發者以更直覺、更語意化的方式操作 token。

筆者大多經驗著重在智能合約開發,對於 DApp 其他部分如前端、後端等等涉略較少,非常歡迎大家在 ethers-token issues 裡交流不同的使用情境 😃


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK