Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion brownie-config.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# use Ganache's forked mainnet mode as the default network
# NOTE: You don't *have* to do this, but it is often helpful for testing
networks:
default: mainnet-fork
default: arb-main-fork

# automatically fetch contract sources from Etherscan
autofetch_sources: True
Expand Down
95 changes: 46 additions & 49 deletions contracts/StrategyCurveTricrypto.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,9 @@ import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/math/Math.sol";

import "./interfaces/curve.sol";
import "./interfaces/yearn.sol";
import {IUniswapV2Router02} from "./interfaces/uniswap.sol";
import {
BaseStrategy,
StrategyParams
} from "@yearnvaults/contracts/BaseStrategy.sol";

interface IUniV3 {
struct ExactInputParams {
bytes path;
address recipient;
uint256 deadline;
uint256 amountIn;
uint256 amountOutMinimum;
}

function exactInput(ExactInputParams calldata params)
external
payable
returns (uint256 amountOut);
}
import { IGauge, IGaugeFactory, ICurveFi } from "./interfaces/curve.sol";
import { IUniswapV2Router02 } from "./interfaces/uniswap.sol";
import { BaseStrategy, StrategyParams } from "@yearnvaults/contracts/BaseStrategy.sol";

abstract contract StrategyCurveBase is BaseStrategy {
using SafeERC20 for IERC20;
Expand All @@ -42,7 +23,10 @@ abstract contract StrategyCurveBase is BaseStrategy {

// Curve stuff
IGauge public constant gauge =
IGauge(0x97E2768e8E73511cA874545DC5Ff8067eB19B787); // Curve gauge contract, most are tokenized, held by strategy
IGauge(0x555766f3da968ecBefa690Ffd49A2Ac02f47aa5f); // Curve gauge contract, most are tokenized, held by strategy

IGaugeFactory public constant gaugeFactory =
IGaugeFactory(0xabC000d88f23Bb45525E447528DBF656A9D55bf5);

// keepCRV stuff
uint256 public keepCRV; // the percentage of CRV we re-lock for boost (in basis points)
Expand Down Expand Up @@ -125,7 +109,22 @@ abstract contract StrategyCurveBase is BaseStrategy {
return balanceOfWant();
}

function _claimRewards() internal {
gaugeFactory.mint(address(gauge));
}

function claimRewards() external onlyVaultManagers {
// Claims any pending CRV
//
// Mints claimable CRV from the factory gauge. Reward tokens are sent to `msg.sender`
// The method claim_rewards() from the old gauge now only applies to third-party tokens.
// There are no third-party tokens in this strategy.
_claimRewards();
}

function prepareMigration(address _newStrategy) internal override {
// Withdraw LP tokens from the gauge. The transfer to the new strategy is done
// by migrate() in BaseStrategy.sol
uint256 _stakedBal = stakedBalance();
if (_stakedBal > 0) {
gauge.withdraw(_stakedBal);
Expand Down Expand Up @@ -207,10 +206,12 @@ contract StrategyCurveTricrypto is StrategyCurveBase {
// these are our approvals and path specific to this contract
wbtc.approve(address(curve), type(uint256).max);
weth.approve(address(curve), type(uint256).max);
usdt.safeApprove(address(curve), type(uint256).max);
usdt.approve(address(curve), type(uint256).max);

// start off with weth
targetToken = address(weth);
//'targetToken' is the token with the least impact on the curve pool at the time of deposit
// or the one with the biggest bonus. 'targetToken' is updated by yearn when granted by
// market conditions. We start off with usdt.
targetToken = address(usdt);
}

/* ========== MUTATIVE FUNCTIONS ========== */
Expand All @@ -225,10 +226,12 @@ contract StrategyCurveTricrypto is StrategyCurveBase {
uint256 _debtPayment
)
{
// harvest our rewards from the gauge
gauge.claim_rewards();
// Claim and get a fresh snapshot of the strategy's CRV balance
_claimRewards();

uint256 crvBalance = crv.balanceOf(address(this));
// if we claimed any CRV, then sell it

// Sell CRV if we have any
if (crvBalance > 0) {
// keep some of our CRV to increase our boost
uint256 sendToVoter = crvBalance.mul(keepCRV).div(FEE_DENOMINATOR);
Expand Down Expand Up @@ -287,34 +290,28 @@ contract StrategyCurveTricrypto is StrategyCurveBase {
forceHarvestTriggerOnce = false;
}

// Sells our CRV for WETH on sushi
// Sells our CRV for WETH or targetToken on sushi
function _sell(uint256 _amount) internal {
address[] memory path;

if (targetToken == address(weth)) {
address[] memory path = new address[](2);
path = new address[](2);
path[0] = address(crv);
path[1] = address(weth);

IUniswapV2Router02(router).swapExactTokensForTokens(
_amount,
uint256(0),
path,
address(this),
block.timestamp
);
} else {
address[] memory path = new address[](3);
path = new address[](3);
path[0] = address(crv);
path[1] = address(weth);
path[2] = targetToken;

IUniswapV2Router02(router).swapExactTokensForTokens(
_amount,
uint256(0),
path,
address(this),
block.timestamp
);
}

IUniswapV2Router02(router).swapExactTokensForTokens(
_amount,
uint256(0),
path,
address(this),
block.timestamp
);
}

/* ========== KEEP3RS ========== */
Expand Down Expand Up @@ -364,7 +361,7 @@ contract StrategyCurveTricrypto is StrategyCurveBase {

// These functions are useful for setting parameters of the strategy that may need to be adjusted.
// Set optimal token to sell harvested funds for depositing to Curve.
// Default is WETH, but can be set to USDT or WBTC as needed by strategist or governance.
// Default is USDT, but can be set to WETH or WBTC as needed by strategist or governance.
function setOptimal(uint256 _optimal) external onlyEmergencyAuthorized {
if (_optimal == 0) {
targetToken = address(weth);
Expand Down
124 changes: 5 additions & 119 deletions contracts/interfaces/curve.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,138 +2,24 @@
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";

interface IGauge {
function deposit(uint256) external;

function balanceOf(address) external view returns (uint256);

function claim_rewards() external;

function claimable_tokens(address) external view returns (uint256);
function withdraw(uint256) external;

function claimable_reward(address _addressToCheck, address _rewardToken)
external
view
returns (uint256);
function claimable_tokens(address) external returns (uint256);
}

function withdraw(uint256) external;
interface IGaugeFactory {
function mint(address _gauge) external;
}

interface ICurveFi {
function get_virtual_price() external view returns (uint256);

function add_liquidity(
// EURt
uint256[2] calldata amounts,
uint256 min_mint_amount
) external payable;

function add_liquidity(
// Compound, sAave
uint256[2] calldata amounts,
uint256 min_mint_amount,
bool _use_underlying
) external payable returns (uint256);

function add_liquidity(
// Iron Bank, Aave
uint256[3] calldata amounts,
uint256 min_mint_amount,
bool _use_underlying
) external payable returns (uint256);

function add_liquidity(
// 3Crv Metapools
address pool,
uint256[4] calldata amounts,
uint256 min_mint_amount
) external;

function add_liquidity(
// Y and yBUSD
uint256[4] calldata amounts,
uint256 min_mint_amount,
bool _use_underlying
) external payable returns (uint256);

function add_liquidity(
// 3pool
uint256[3] calldata amounts,
uint256 min_mint_amount
) external payable;

function add_liquidity(
// sUSD
uint256[4] calldata amounts,
uint256 min_mint_amount
) external payable;

function remove_liquidity_imbalance(
uint256[2] calldata amounts,
uint256 max_burn_amount
) external;

function remove_liquidity(uint256 _amount, uint256[2] calldata amounts)
external;

function remove_liquidity_one_coin(
uint256 _token_amount,
int128 i,
uint256 min_amount
) external;

function exchange(
int128 from,
int128 to,
uint256 _from_amount,
uint256 _min_to_amount
) external;

function balances(uint256) external view returns (uint256);

function get_dy(
int128 from,
int128 to,
uint256 _from_amount
) external view returns (uint256);

// EURt
function calc_token_amount(uint256[2] calldata _amounts, bool _is_deposit)
external
view
returns (uint256);

// 3Crv Metapools
function calc_token_amount(
address _pool,
uint256[4] calldata _amounts,
bool _is_deposit
) external view returns (uint256);

// sUSD, Y pool, etc
function calc_token_amount(uint256[4] calldata _amounts, bool _is_deposit)
external
view
returns (uint256);

// 3pool, Iron Bank, etc
function calc_token_amount(uint256[3] calldata _amounts, bool _is_deposit)
external
view
returns (uint256);

function calc_withdraw_one_coin(uint256 amount, int128 i)
external
view
returns (uint256);
}

interface ICrvV3 is IERC20 {
function minter() external view returns (address);
}

interface IMinter {
function mint(address) external;
}
43 changes: 0 additions & 43 deletions contracts/interfaces/yearn.sol

This file was deleted.

Loading