This repository has been archived by the owner on Mar 3, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
ConvexAdapter.sol
112 lines (91 loc) · 4.46 KB
/
ConvexAdapter.sol
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2023 Tokemak Foundation. All rights reserved.
pragma solidity 0.8.17;
import { IERC20 } from "openzeppelin-contracts/token/ERC20/IERC20.sol";
import { IBaseRewardPool } from "src/interfaces/external/convex/IBaseRewardPool.sol";
import { IConvexBooster } from "src/interfaces/external/convex/IConvexBooster.sol";
import { LibAdapter } from "src/libs/LibAdapter.sol";
library ConvexStaking {
event DeployLiquidity(address lpToken, address staking, uint256 poolId, uint256 amount);
event WithdrawLiquidity(address lpToken, address staking, uint256 amount);
error withdrawStakeFailed();
error DepositAndStakeFailed();
error PoolIdLpTokenMismatch();
error PoolIdStakingMismatch();
error MustBeMoreThanZero();
error ArraysLengthMismatch();
error BalanceMustIncrease();
error MinLpAmountNotReached();
error LpTokenAmountMismatch();
error NoNonZeroAmountProvided();
error InvalidBalanceChange();
error InvalidAddress(address);
/**
* @notice Deposits and stakes Curve LP tokens to Convex
* @dev Calls to external contract
* @param booster Convex Booster address
* @param lpToken Curve LP token to deposit
* @param staking Convex reward contract associated with the Curve LP token
* @param poolId Convex poolId for the associated Curve LP token
* @param amount Quantity of Curve LP token to deposit and stake
*/
function depositAndStake(
IConvexBooster booster,
address lpToken,
address staking,
uint256 poolId,
uint256 amount
) public {
if (address(booster) == address(0)) revert InvalidAddress(address(booster));
if (lpToken == address(0)) revert InvalidAddress(address(lpToken));
if (staking == address(0)) revert InvalidAddress(address(staking));
if (amount == 0) revert MustBeMoreThanZero();
emit DeployLiquidity(lpToken, staking, poolId, amount);
_validatePoolInfo(booster, poolId, lpToken, staking);
LibAdapter._approve(IERC20(lpToken), address(booster), amount);
IBaseRewardPool rewards = IBaseRewardPool(staking);
uint256 rewardsBeforeBalance = rewards.balanceOf(address(this));
_runDeposit(booster, poolId, amount);
if (rewards.balanceOf(address(this)) - rewardsBeforeBalance != amount) {
revert BalanceMustIncrease();
}
}
/**
* @notice Withdraws a Curve LP token from Convex
* @dev Does not claim available rewards
* @dev Calls to external contract
* @param lpToken Curve LP token to withdraw
* @param staking Convex reward contract associated with the Curve LP token
* @param amount Quantity of Curve LP token to withdraw
*/
function withdrawStake(address lpToken, address staking, uint256 amount) public {
// slither-disable-start incorrect-equality
if (lpToken == address(0)) revert InvalidAddress(lpToken);
if (staking == address(0)) revert InvalidAddress(staking);
if (amount == 0) revert MustBeMoreThanZero();
// slither-disable-end incorrect-equality
IERC20 lpTokenErc = IERC20(lpToken);
uint256 beforeLpBalance = lpTokenErc.balanceOf(address(this));
IBaseRewardPool rewards = IBaseRewardPool(staking);
emit WithdrawLiquidity(lpToken, staking, amount);
bool success = rewards.withdrawAndUnwrap(amount, false);
if (!success) revert withdrawStakeFailed();
uint256 updatedLpBalance = lpTokenErc.balanceOf(address(this));
if (updatedLpBalance - beforeLpBalance != amount) {
revert BalanceMustIncrease();
}
}
/// @dev Separate function to avoid stack-too-deep errors
function _runDeposit(IConvexBooster booster, uint256 poolId, uint256 amount) private {
bool success = booster.deposit(poolId, amount, true);
if (!success) revert DepositAndStakeFailed();
}
/// @dev Separate function to avoid stack-too-deep errors
function _validatePoolInfo(IConvexBooster booster, uint256 poolId, address lpToken, address staking) private view {
// Partial return values are intentionally ignored. This call provides the most efficient way to get the data.
// slither-disable-next-line unused-return
(address poolLpToken,,, address crvRewards,,) = booster.poolInfo(poolId);
if (lpToken != poolLpToken) revert PoolIdLpTokenMismatch();
if (staking != crvRewards) revert PoolIdStakingMismatch();
}
}