Curve.Fi是一組規模龐大的DEFi協議,這個教程的目的是幫助你關注智能合約開發的現代方法,以及如何在本身的Defi應用中集成Curve.Fi這種大型協議的關鍵點。git
用熟悉的語言學習 以太坊合約與DApp開發 :Java | Php | Python | .Net / C# | Golang |Node.JS | Flutter / Dartgithub
一、Curve.Fi開發教程的組織方式
是的,我已經說過咱們將深刻研究代碼。儘管咱們不是在談論AMM模型的數學運算,也不是在Curve.Fi合約中使用的其餘一些特定技巧,可是咱們仍然須要瞭解一些內容。固然,這不是在談論成功的DeFi開發-我沒有給出提示。這是我經驗的一部分,在這裏我將分享一些有關Curve智能合約的基本架構以及咱們如何與這些架構集成的知識。實際上,下圖中包含了本教程的所有內容:架構
咱們研究的是Y-Pool,它以一種簡單明瞭的方式組織。存款(Deposit)合約將你的資金打包成Y-Token,而後將其發送到兌換(Swap)合約,兌換合約爲用戶生成LP代幣。若是你要提取流通性份額以及所賺取的收益,則合約會執行相同的操做,可是方式相反。這一切都與金融合約有關(固然,若是咱們對池平衡和股數計算背後的複雜邏輯選擇視而不見)。app
此外,咱們還有Gauge和Minter合同,它們是Curve.Fi DAO的一部分。這些合約使你能夠得到CRV代幣獎勵並將其抵押,以便得到協議治理的投票權。單元測試
在咱們充分了解這些須要交互的合約後,就能夠開始咱們的開發了。學習
二、從Curve.Fi用戶交互界面開始
你可能還記得,咱們正在處理一些使用Vyper開發的外部合約。爲了與這些合約交互,咱們須要建立一些接口。這並非最困難的工做:只須要仔細查看原始合約並挑出將要調用的方法便可。測試
讓咱們將從存款合約開始。咱們須要資金進出的方法,以及一些數據查看界面(例如,查看已註冊的代幣及其Y對應代幣)。ui
contract ICurveFi_DepositY { function add_liquidity(uint256[4] calldata uamounts, uint256 min_mint_amount) external; function remove_liquidity(uint256 _amount, uint256[4] calldata min_uamounts) external; function remove_liquidity_imbalance(uint256[4] calldata uamounts, uint256 max_burn_amount) external; function coins(int128 i) external view returns (address); function underlying_coins(int128 i) external view returns (address); function underlying_coins() external view returns (address[4] memory); function curve() external view returns (address); function token() external view returns (address); }
而後用相同的方法處理兌換合約(你可能還記得,該合約爲用戶鑄造LP代幣)。this
contract ICurveFi_Gauge { function lp_token() external view returns(address); function crv_token() external view returns(address); function balanceOf(address addr) external view returns (uint256); function deposit(uint256 _value) external; function withdraw(uint256 _value) external; function claimable_tokens(address addr) external returns (uint256); function minter() external view returns(address); //use minter().mint(gauge_addr) to claim CRV function integrate_fraction(address _for) external view returns(uint256); function user_checkpoint(address _for) external returns(bool); }
如今該處理DAO的主要合約-流動性計量器合約。它執行復雜的功能,但咱們主要須要用於建立檢查點的方法以及查看Minter和CRV代幣地址的界面。3d
contract ICurveFi_Gauge { function lp_token() external view returns(address); function crv_token() external view returns(address); function balanceOf(address addr) external view returns (uint256); function deposit(uint256 _value) external; function withdraw(uint256 _value) external; function claimable_tokens(address addr) external returns (uint256); function minter() external view returns(address); //use minter().mint(gauge_addr) to claim CRV function integrate_fraction(address _for) external view returns(uint256); function user_checkpoint(address _for) external returns(bool); }
還有從用戶界面的角度來看實際上是最簡單的合約— Minter。實際上,咱們只須要minter方法自己,以及一個能夠查看有效獎勵的方法。
contract ICurveFi_Minter { function mint(address gauge_addr) external; function minted(address _for, address gauge_addr) external view returns(uint256); function toggle_approve_mint(address minting_user) external; function token() external view returns(address); }
最後一個是YToken接口,不過它並不是最不重要,由於咱們要交互的就是Curve的Y池。YToken是一個簡單的ERC20接口,幾乎沒有其餘額外的方法。
contract IYERC20 { //ERC20 functions // // //Y-token functions function deposit(uint256 amount) external; function withdraw(uint256 shares) external; function getPricePerFullShare() external view returns (uint256); function token() external returns(address); }
如今咱們準備建立一些代碼來與此協議交互。
三、基於Curve.Fi以正確的順序轉移資金
咱們的實驗合約的主要目標是展現如何將Curve協議做爲資金流終點來組織資金的流動。所以,咱們將有兩種主要方法:一種用於完整的存款流程(具備從Curve.Fi可得到的全部好處),另外一種用於提款流程。
讓咱們從存款開始。
function multiStepDeposit(uint256[4] memory _amounts) public { address[4] memory stablecoins = ICurveFi_DepositY(curveFi_Deposit).underlying_coins(); for (uint256 i = 0; i < stablecoins.length; i++) { IERC20(stablecoins[i]).safeTransferFrom(_msgSender(), address(this), _amounts[i]); IERC20(stablecoins[i]).safeApprove(curveFi_Deposit, _amounts[i]); } //Step 1 - deposit stablecoins and get Curve.Fi LP tokens ICurveFi_DepositY(curveFi_Deposit).add_liquidity(_amounts, 0); //0 to mint all Curve has to //Step 2 - stake Curve LP tokens into Gauge and get CRV rewards uint256 curveLPBalance = IERC20(curveFi_LPToken).balanceOf(address(this)); IERC20(curveFi_LPToken).safeApprove(curveFi_LPGauge, curveLPBalance); ICurveFi_Gauge(curveFi_LPGauge).deposit(curveLPBalance); //Step 3 - get all the rewards (and make whatever you need with them) crvTokenClaim(); uint256 crvAmount = IERC20(curveFi_CRVToken).balanceOf(address(this)); IERC20(curveFi_CRVToken).safeTransfer(_msgSender(), crvAmount); }
正像你看見的,咱們在multiStepDeposit()
方法中執行了幾個動做。首先,將咱們的資金(在本例中爲選定的穩定幣)存入Deposit合約,以便接收Curve LP代幣。第二步是將LP代幣存入Gauge合約,以便得到CRV代幣獎勵。第三步取決於你本身 —— 可使用CRV獎勵作任何想作的事情。
實際上,相同的方案也適用於multiStepWithdraw()方法,但順序相反。
function multiStepWithdraw(uint256[4] memory _amounts) public { address[4] memory stablecoins = ICurveFi_DepositY(curveFi_Deposit).underlying_coins(); //Step 1 - Calculate amount of Curve LP-tokens to unstake uint256 nWithdraw; uint256 i; for (i = 0; i < stablecoins.length; i++) { nWithdraw = nWithdraw.add(normalize(stablecoins[i], _amounts[i])); } uint256 withdrawShares = calculateShares(nWithdraw); //Check if you can re-use unstaked LP tokens uint256 notStaked = curveLPTokenUnstaked(); if (notStaked > 0) { withdrawShares = withdrawShares.sub(notStaked); } //Step 2 - Unstake Curve LP tokens from Gauge ICurveFi_Gauge(curveFi_LPGauge).withdraw(withdrawShares); //Step 3 - Withdraw stablecoins from CurveDeposit IERC20(curveFi_LPToken).safeApprove(curveFi_Deposit, withdrawShares); ICurveFi_DepositY(curveFi_Deposit).remove_liquidity_imbalance(_amounts, withdrawShares); //Step 4 - Send stablecoins to the requestor // }
是的,解決方案很是簡單,某種程度上看起來很笨拙,而且存在幾個明顯的漏洞 —— 雖然這些代碼僅用於演示目的。你能夠添加所需的全部檢查,將階段拆分爲不一樣的方法,爲方法設置不一樣的權限,並執行使你的DeFi項目成功所需的全部其餘工做。
四、測試Curve.Fi解決方案
教程的最後一步是添加幾個單元測試,以驗證解決方案是否有效。雖然在這裏咱們面臨幾個問題。第一個(也是主要的)問題是Curve.Fi協議環境。爲了測試解決方案,咱們須要在本地環境(在咱們的例子中爲Ganache)上模擬完整的Curve協議。因爲這是一組複雜的合約,並且是在Vyper上編寫的,所以咱們不能僅將它們編譯並部署到咱們的Ganache節點中。
我已經完成了一些工做,並準備了Curve協議的測試存根,能夠將其與你的項目一塊兒編譯並部署你的測試網上。除了出於測試目的的幾種簡化,這些測試存根與原始的Curve協議徹底相同。你能夠在這裏下載。
所以,咱們能夠跳過將Vyper代碼轉換爲可測試的Solidity合約的無聊部分,直接查看單元測試的輸出:
好了!咱們已經得到了集成複雜的DeFi協議的所有經驗。在此基礎上,盡情開啓你的想象力去創造吧!
原文連接:Curve.Fi對接教程 — 匯智網