Uniswap代碼揭祕:7大合約開發技巧助力Defi新手

從Uniswap代碼中學到的合約開發技巧

近期在編寫去中心化交易所開發教程時,參考了Uniswap V3的代碼實現,學習到了許多有價值的知識點。作爲首次嘗試開發Defi合約的開發者,這些技巧對想要學習合約開發的新手會很有幫助。

Web3 新手系列:我從 Uniswap 代碼中學到的合約開發小技巧

可預測的合約部署地址

通常部署合約得到的地址看似隨機,因爲與nonce有關。但在某些情況下,我們需要通過交易對和相關信息推斷出合約地址,比如判斷交易權限或獲取池子地址。

Uniswap採用CREATE2方式創建合約,通過添加salt參數使生成的地址可預測。新地址的計算邏輯爲:hash("0xFF",創建者地址, salt, initcode)。

Web3 新手系列:我從 Uniswap 代碼中學到的合約開發小技巧

巧用回調函數

Solidity中合約可以互相調用。在某些場景下,A調用B的方法,B在被調用的方法中回調A是很有用的。

Uniswap中,調用UniswapV3Pool合約的swap方法交易時,它會回調swapCallback,傳入本次交易實際需要的Token。調用方需要在回調中將所需Token轉入UniswapV3Pool,而不是將swap方法拆分爲兩部分。這確保了swap方法的安全性和完整執行,無需繁瑣的變量記錄。

用異常傳遞信息,用try catch實現交易預估

Uniswap的Quoter合約中,將UniswapV3Pool的swap方法用try catch包裹執行。這是爲了模擬swap方法預估交易所需Token,但預估時不會實際產生Token交換,所以會報錯。

Uniswap通過在交易回調函數中拋出特殊錯誤,然後捕獲這個錯誤,從錯誤信息中解析出所需信息。這種方法看似取巧,但很實用,無需爲預估交易需求改造swap方法,邏輯也更簡單。

Web3 新手系列:我從 Uniswap 代碼中學到的合約開發小技巧

使用大數解決精度問題

Uniswap代碼中有許多計算邏輯,如根據當前價格和流動性計算交換的Token。爲避免除法操作丟失精度,計算過程經常使用"<< FixedPoint96.RESOLUTION"操作,即左移96位,相當於乘以2^96。

左移後再進行除法運算,可在正常交易不溢出的情況下保證精度。雖然理論上仍會有最小單位的精度丟失,但這是可以接受的。

用Share方式計算收益

Uniswap需要記錄LP(流動性提供者)的手續費收益。爲避免每次交易都給每個LP記錄手續費而消耗大量Gas,Uniswap採用了巧妙的方法。

Position結構體中包含feeGrowthInside0LastX128和feeGrowthInside1LastX128,記錄了每個頭寸上次提取手續費時每個流動性應獲得的手續費。只需記錄總手續費和每個流動性應分配的手續費,LP提取時按持有的流動性計算可提取的手續費即可。

Web3 新手系列:我從 Uniswap 代碼中學到的合約開發小技巧

鏈上信息獲取策略

並非所有信息都需要從鏈上獲取。鏈上存儲相對昂貴,許多信息可存儲在普通數據庫中,定期從鏈上同步。

如交易池列表、交易池信息等可存儲在普通數據庫中,無需實時調用鏈或節點服務的RPC接口。當然,關鍵交易仍在鏈上進行。

合約拆分與標準合約利用

一個項目可能包含多個實際部署的合約。即使實際部署只有一個合約,代碼也可通過繼承方式拆分爲多個合約維護。

例如,Uniswap的NonfungiblePositionManager合約繼承了多個合約。使用OpenZeppelin的ERC721合約,既方便通過NFT管理頭寸,又能提高開發效率。

結語

實踐是最好的學習方法。嘗試實現一個簡易版去中心化交易所,能深入理解Uniswap的代碼實現,學習到更多實際項目中的知識點。如果對Web3和Defi項目開發感興趣,可以參考相關實戰課程,逐步完成一個簡易版交易所。

Web3 新手系列:我從 Uniswap 代碼中學到的合約開發小技巧

查看原文
此頁面可能包含第三方內容,僅供參考(非陳述或保證),不應被視為 Gate 認可其觀點表述,也不得被視為財務或專業建議。詳見聲明
  • 讚賞
  • 3
  • 分享
留言
0/400
BlockchainBouncervip
· 07-06 09:29
代码分析精髓所在
回復0
RektButSmilingvip
· 07-03 10:38
太对了,新手教学
回復0
薛定谔的gasvip
· 07-03 10:38
值得参考学习
回復0
交易,隨時隨地
qrCode
掃碼下載 Gate APP
社群列表
繁體中文
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)