Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Curve and Convex adaptors #74

Open
wants to merge 53 commits into
base: main
Choose a base branch
from
Open
Changes from 4 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
e7869b2
Convex adaptor initialization
Oct 29, 2022
8a66a48
rename test faucet
Oct 29, 2022
f60172b
Curve3PoolAdaptor
Oct 29, 2022
a282be7
change location of curve 3 pool adaptor
Oct 29, 2022
f362087
add mock tests for curve pool
Oct 29, 2022
2f024d7
new methods and test start
Oct 29, 2022
a9cddbd
Curve3PoolAdaptor balanceOf
federava Oct 29, 2022
9b713cb
Merge branch 'main' of https://github.com/cookiesanddudes/cellar-cont…
federava Oct 29, 2022
e6b4ece
add interface, fix balanceOf()
Oct 29, 2022
3ce7ac8
fix interface
Oct 29, 2022
90a6479
updates on the adaptor
Oct 29, 2022
b006317
fix balance of usdc
Oct 29, 2022
87c91f0
simplify test, allow deposits
Oct 29, 2022
938a96a
failed test
Oct 29, 2022
6805c83
remove 42
Oct 29, 2022
ecc8a76
fix interfaces and test
Oct 29, 2022
e023138
fix: ICurvePool
federava Oct 29, 2022
a9c663e
added assertEq
Oct 29, 2022
c81d814
Merge branch 'main' of github-dude:cookiesanddudes/cellar-contracts
Oct 29, 2022
778b848
added test condition
Oct 29, 2022
e12c57f
remove position in one coin
Oct 29, 2022
c8cefcf
disallow deposits and withdrawals()
Oct 29, 2022
359b187
add close and take
Oct 29, 2022
0f203be
test: withdrawableFrom
federava Oct 29, 2022
375dd3e
add position and take position functions
Oct 29, 2022
f54534b
Merge branch 'main' of github-dude:cookiesanddudes/cellar-contracts
Oct 29, 2022
09228bc
comment unimplemented function
Oct 29, 2022
a97ef86
remove infinite for loop
Oct 29, 2022
7bec56b
test adding and taking from curve
Oct 29, 2022
36e1329
convex setup
Oct 29, 2022
b482e38
update tests
Oct 29, 2022
d9b8c82
Convex strat
Oct 29, 2022
5473a8e
complete IBooster
federava Oct 30, 2022
42304b3
withdrawableFrom
federava Oct 30, 2022
c527277
convex adaptor
Oct 30, 2022
7c1b8e5
NatSpec Curve3PoolAdaptor
federava Oct 30, 2022
c168644
Merge branch 'main' of https://github.com/cookiesanddudes/cellar-cont…
federava Oct 30, 2022
d8af9b7
test: revert Curve3Pool
federava Oct 30, 2022
920f4c8
convex test start
Oct 30, 2022
8989751
Merge branch 'main' of github-dude:cookiesanddudes/cellar-contracts
Oct 30, 2022
cf2788b
add convex test... working
Oct 30, 2022
bba8b2b
add open and close test
Oct 30, 2022
2a655ac
convex tests
Oct 30, 2022
ae3d366
rewards!
Oct 30, 2022
d15ed49
fix comment
Oct 30, 2022
e12ad24
adaptors
Oct 30, 2022
76f4ec4
linting
Oct 30, 2022
f492862
comments
Oct 30, 2022
af3079b
feature: Curve2Pool
federava Oct 30, 2022
ae78a81
Merge branch 'main' of https://github.com/cookiesanddudes/cellar-cont…
federava Oct 30, 2022
ebeb533
add authors
Oct 30, 2022
d5991bc
remove unused variables
Oct 30, 2022
f4d4ff4
final linting
Oct 30, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 37 additions & 9 deletions src/modules/adaptors/Curve/Curve3PoolAdaptor.sol
Original file line number Diff line number Diff line change
@@ -64,7 +64,6 @@ contract Curve3PoolAdaptor is BaseAdaptor {
revert BaseAdaptor__UserWithdrawsNotAllowed();
}


/**
* @notice User withdraws are not allowed so this position must return 0 for withdrawableFrom.
*/
@@ -74,6 +73,8 @@ contract Curve3PoolAdaptor is BaseAdaptor {

/**
* @notice Calculates this positions LP tokens underlying worth in terms of `token0`.
* @notice Curve pools provide a calculation where the amount returned considers the swapping of token1 and token2
* for token0 considering fees.
*/
function balanceOf(bytes memory adaptorData) public view override returns (uint256) {
(ICurvePool pool, ERC20 lpToken) = abi.decode(adaptorData, (ICurvePool, ERC20));
@@ -96,9 +97,14 @@ contract Curve3PoolAdaptor is BaseAdaptor {
}

//============================================ Strategist Functions ===========================================

/**
* @notice Allows strategist to open up arbritray Curve positions.
* @notice Allows to send any combination of token0, token1 and token2 which the pool will
* balance on deposit.
* @notice If minted lp tokens is less than minimumMintAmount function will revert.
* @param amounts token0, token1, and token2 amounts to be deposited.
* @param minimumMintAmount minting at least this amount of lp tokens.
* @param pool specifies the interface of the pool
*/
function openPosition(
uint256[3] memory amounts,
@@ -118,13 +124,17 @@ contract Curve3PoolAdaptor is BaseAdaptor {

pool.add_liquidity(amounts, minimumMintAmount);
}


error Curve3PoolAdaptor__CallClosePosition();
/**
* @notice Strategist attempted to remove all of a positions liquidity using `takeFromPosition`,
* but they need to use `closePosition`.
* @notice If receiving amount of token0 is less than minimumMintAmount function will revert.
* @param amount lp token amount to be burned.
* @param minimumAmount receiving at least this amount of token0.
* @param pool specifies the interface of the pool
* @param lpToken specifies the interface of the lp token
*/
error Curve3PoolAdaptor__CallClosePosition();

function takeFromPosition(
uint256 amount,
uint256 minimumAmount,
@@ -136,6 +146,13 @@ contract Curve3PoolAdaptor is BaseAdaptor {
_takeFromPosition(amount, minimumAmount, pool);
}

/**
* @notice Executes the removal of liquidity in one coin: token0.
* @notice If receiving amount of token0 is less than minimumMintAmount function will revert.
* @param amount lp token amount to be burned.
* @param minimumAmount receiving at least this amount of token0.
* @param pool specifies the interface of the pool
*/
function _takeFromPosition(
uint256 amount,
uint256 minimumAmount,
@@ -144,12 +161,14 @@ contract Curve3PoolAdaptor is BaseAdaptor {
pool.remove_liquidity_one_coin(amount, 0, minimumAmount);
}

error Curve3PoolAdaptor__PositionClosed();
/**
* @notice Strategist attempted to remove all of a positions liquidity using `takeFromPosition`,
* but they need to use `closePosition`.
* @notice Strategist use `closePosition` to remove all of a positions liquidity.
* @notice If receiving amount of token0 is less than minimumMintAmount function will revert.
* @param minimumAmount receiving at least this amount of token0.
* @param pool specifies the interface of the pool
* @param lpToken specifies the interface of the lp token
*/
error Curve3PoolAdaptor__PositionClosed();

function closePosition(
uint256 minimumAmount,
ICurvePool pool,
@@ -161,6 +180,15 @@ contract Curve3PoolAdaptor is BaseAdaptor {
_takeFromPosition(amountToWithdraw, minimumAmount, pool);
}

/**
* @notice Allows strategist to add liquidity to a Curve position.
* @notice Allows to send any combination of token0, token1 and token2 which the pool will
* balance on deposit.
* @notice If minted lp tokens is less than minimumMintAmount function will revert.
* @param amounts token0, token1, and token2 amounts to be deposited.
* @param minimumMintAmount minting at least this amount of lp tokens.
* @param pool specifies the interface of the pool
*/
function addToPosition(
uint256[3] memory amounts,
uint256 minimumMintAmount,
85 changes: 74 additions & 11 deletions test/testAdaptors/Curve3Pool.t.sol
Original file line number Diff line number Diff line change
@@ -93,16 +93,7 @@ contract Curve3PoolTest is Test {
stdstore.target(address(cellar)).sig(cellar.shareLockPeriod.selector).checked_write(uint256(0));
}

function testFaucet() external {
uint256 amount = 100e18;
deal(address(DAI), address(this), amount);
assertEq(
DAI.balanceOf(address(this)),
amount,
"Should be able to deal some tokens"
);
}

// ========================================== POSITION MANAGEMENT TEST ==========================================
function testOpenPosition() external {
deal(address(DAI), address(cellar), 100_000e18);

@@ -237,7 +228,7 @@ contract Curve3PoolTest is Test {
assertEq(curve3PoolAdaptor.balanceOf(abi.encode(curve3Pool, LP3CRV)), 0);
}

function testOpeningAddingAndTakingFromPosition() external {
function testOpeningAddingAndTakingFromPosition() external {
deal(address(DAI), address(cellar), 100_000e18);
deal(address(USDC), address(cellar), 100_000e6);
deal(address(USDT), address(cellar), 100_000e6);
@@ -309,6 +300,78 @@ function testOpeningAddingAndTakingFromPosition() external {
);
}

// ========================================== REVERT TEST ==========================================
function testMinimalLPTokenMintUnreached() external {
deal(address(DAI), address(cellar), 100_000e18);

// Use `callOnAdaptor` to deposit LP into curve pool
Cellar.AdaptorCall[] memory data = new Cellar.AdaptorCall[](1);
bytes[] memory adaptorCalls = new bytes[](1);
adaptorCalls[0] = _createBytesDataToOpenPosition(
1e18,
0,
0,
100e18
);

data[0] = Cellar.AdaptorCall({ adaptor: address(curve3PoolAdaptor), callData: adaptorCalls });

vm.expectRevert(
bytes(
abi.encodePacked(
"Slippage screwed you"
)
)
);
cellar.callOnAdaptor(data);
}


function testMinimalToken0WithdrawMintUnreached() external {
deal(address(DAI), address(cellar), 100_000e18);
deal(address(USDC), address(cellar), 100_000e6);
deal(address(USDT), address(cellar), 100_000e6);

// Use `callOnAdaptor` to deposit LP into curve pool
Cellar.AdaptorCall[] memory data = new Cellar.AdaptorCall[](1);
bytes[] memory adaptorCalls = new bytes[](1);
adaptorCalls[0] = _createBytesDataToOpenPosition(
1e18,
1e6,
1e6,
0
);

data[0] = Cellar.AdaptorCall({ adaptor: address(curve3PoolAdaptor), callData: adaptorCalls });

cellar.callOnAdaptor(data);

uint256 lpBalance = LP3CRV.balanceOf(address(cellar));
uint256 daiBalanceBefore = DAI.balanceOf(address(cellar));

// assert balanceOf is bigger than 0
vm.prank(address(cellar));
assertGe(curve3PoolAdaptor.balanceOf(abi.encode(curve3Pool, LP3CRV)), 0);

// assert LP is bigger than 0
assertGe(lpBalance, 0);

// Now, close the position
adaptorCalls = new bytes[](1);
adaptorCalls[0] = _createBytesDataToClosePosition(100e18);

data[0] = Cellar.AdaptorCall({ adaptor: address(curve3PoolAdaptor), callData: adaptorCalls });
vm.expectRevert(
bytes(
abi.encodePacked(
"Not enough coins removed"
)
)
);
cellar.callOnAdaptor(data);
}

// ======================================= AUXILIAR FUNCTIONS ======================================

function _createBytesDataToOpenPosition(
uint256 amount0,