10

Curve.Fi对接教程

 3 years ago
source link: http://blog.hubwiz.com/2020/12/08/curve-fi-integrate/
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.
区块链开发课程精选

Curve.Fi是一组规模庞大的DEFi协议,这个教程的目的是帮助 你关注智能合约开发的现代方法,以及如何在自己的Defi 应用中集成Curve.Fi这种大型协议的关键点。

用自己熟悉的语言学习 以太坊智能合约与DApp开发Java | Php | Python | .Net / C# | Golang | Node.JS | Flutter / Dart

1、Curve.Fi开发教程的组织方式

是的,我已经说过我们将深入研究代码。尽管我们不是在谈论AMM模型的数学运算, 也不是在Curve.Fi合约中使用的其他一些特定技巧,但是我们仍然需要了解 一些内容。当然,这不是在谈论成功的DeFi开发-我没有给出提示。这是我经验的一部分, 在这里我将分享一些有关Curve智能合约的基本架构以及我们如何与这些架构集成的知识。 实际上,下图中包含了本教程的全部内容:

curve.fi协议集成教程

我们研究的是Y-Pool,它以一种简单明了的方式组织。存款(Deposit)合约将你的资金 打包成Y-Token,然后将其发送到兑换(Swap)合约,兑换合约为用户生成LP代币。 如果你要提取流通性份额以及所赚取的收益,则合约会执行相同的操作,但是方式相反。 这一切都与金融合约有关(当然,如果我们对池平衡和股数计算背后的复杂逻辑选择视而不见)。

此外,我们还有Gauge和Minter合同,它们是Curve.Fi DAO的一部分。这些合约使你可以 获得CRV代币奖励并将其抵押,以便获得协议治理的投票权。

在我们充分了解这些需要交互的合约后,就可以开始我们的开发了。

2、从Curve.Fi用户交互界面开始

你可能还记得,我们正在处理一些使用Vyper开发的外部合约。为了与这些合约交互,我们需要 创建一些接口。这并不是最困难的工作:只需要仔细查看原始合约并挑出将要调用的方法即可。

让我们将从存款合约开始。我们需要资金进出的方法,以及一些数据查看界面(例如,查看已 注册的代币及其Y对应代币)。

1
2
3
4
5
6
7
8
9
10
11
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代币)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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代币地址的界面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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方法本身,以及一个可以查看有效奖励的方法。

1
2
3
4
5
6
7
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接口,几乎没有其他额外的方法。

1
2
3
4
5
6
7
8
9
10
11
12
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);
}

现在我们准备创建一些代码来与此协议交互。

3、基于Curve.Fi以正确的顺序转移资金

我们的实验合约的主要目标是展示如何将Curve协议作为资金流终点来组织资金的流动。 因此,我们将有两种主要方法:一种用于完整的存款流程(具有从Curve.Fi可获得的所有好处), 另一种用于提款流程。

让我们从存款开始。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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()方法,但顺序相反。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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项目成功所需的所有其他工作。

4、测试Curve.Fi解决方案

教程的最后一步是添加几个单元测试,以验证解决方案是否有效。虽然在这里我们面临几个问题。 第一个(也是主要的)问题是Curve.Fi协议环境。为了测试解决方案,我们需要在本地环境(在 我们的例子中为Ganache)上模拟完整的Curve协议。由于这是一组复杂的合约,而且是在Vyper上 编写的,因此我们不能仅将它们编译并部署到我们的Ganache节点中。

我已经完成了一些工作,并准备了Curve协议的测试存根,可以将其与你的项目一起编译并部署在 你的测试网上。除了出于测试目的的几种简化,这些测试存根与原始的Curve协议完全相同。你可以 在这里下载。

因此,我们可以跳过将Vyper代码转换为可测试的Solidity合约的无聊部分,直接查看单元测试的 输出:

curve.fi协议集成教程

好了!我们已经获得了集成复杂的DeFi协议的全部经验。在此基础上,尽情开启你的想象力去创造吧!


原文链接:How to Integrate the Curve.Fi Protocol Into Your DeFi Protocol

汇智网翻译整理,转载请标明出处


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK