Skip to content

Commit

Permalink
updates following review from strategists and security on dudesahn#8
Browse files Browse the repository at this point in the history
  • Loading branch information
pata.eth committed May 23, 2022
1 parent 54fca6b commit 6d40b6e
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 238 deletions.
127 changes: 58 additions & 69 deletions contracts/StrategyCurveGeist.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +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 IBaseFee {
function isCurrentBaseFeeAcceptable() external view returns (bool);
}

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 @@ -46,10 +23,10 @@ abstract contract StrategyCurveBase is BaseStrategy {

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

IGaugeFactory public constant gaugeFactory =
IGaugeFactory(0xabC000d88f23Bb45525E447528DBF656A9D55bf5);
IGaugeFactory(0xabC000d88f23Bb45525E447528DBF656A9D55bf5);

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

function claimRewards() internal {
// Claims any pending CRV
//
// Mints claimable CRV from the factory gauge. Reward tokens are sent to `msg.sender`
gaugeFactory.mint(address(gauge));

// harvest third-party rewards from the gauge, if any
gauge.claim_rewards();
}

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 @@ -204,10 +193,8 @@ contract StrategyCurveGeist is StrategyCurveBase {
address spirit = 0x16327E3FbDaCA3bcF7E38F5Af2599D2DDc33aE52;
want.approve(address(gauge), type(uint256).max);
crv.approve(spooky, type(uint256).max);
wftm.approve(spooky, type(uint256).max);
geist.approve(spooky, type(uint256).max);
crv.approve(spirit, type(uint256).max);
wftm.approve(spirit, type(uint256).max);
geist.approve(spirit, type(uint256).max);

// set our strategy's name
Expand All @@ -218,13 +205,35 @@ contract StrategyCurveGeist is StrategyCurveBase {
usdc.approve(address(curve), type(uint256).max);
fusdt.safeApprove(address(curve), type(uint256).max);

// start off with fusdt
targetToken = address(fusdt);
// start off with usdc, determined by amount of bonus paid by the LP, if any
targetToken = address(usdc);
}

/* ========== MUTATIVE FUNCTIONS ========== */
// these will likely change across different wants.

function claimAndTransferRewards(address _targetAdress)
external
onlyVaultManagers
{
require(_targetAdress != address(0));

// Claim any pending rewards and transfer CRV balance to the new strategy
claimRewards();

uint256 crvBalance = crv.balanceOf(address(this));

if (crvBalance > 0) {
crv.safeTransfer(_targetAdress, crvBalance);
}

uint256 geistBalance = geist.balanceOf(address(this));

if (geistBalance > 0) {
geist.safeTransfer(_targetAdress, geistBalance);
}
}

function prepareReturn(uint256 _debtOutstanding)
internal
override
Expand All @@ -234,17 +243,14 @@ contract StrategyCurveGeist is StrategyCurveBase {
uint256 _debtPayment
)
{
// Mint CRV from the gauge factory. CRV is then transfered to the strategy (msg.sender)
gaugeFactory.mint(address(gauge));
// Claim and get a fresh snapshot of the strategy's CRV and GEIST balance
claimRewards();

uint256 crvBalance = crv.balanceOf(address(this));

// harvest third-party rewards from the gauge, if any
gauge.claim_rewards();

uint256 wftmBalance = wftm.balanceOf(address(this));
uint256 geistBalance = geist.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 All @@ -260,12 +266,8 @@ contract StrategyCurveGeist is StrategyCurveBase {
_sellToken(address(crv), crvBalance);
}
}
// sell WFTM if we have any
if (wftmBalance > 0) {
_sellToken(address(wftm), wftmBalance);
}

// sell the rest of our CRV
// Sell GEIST if we have any
if (geistBalance > 0) {
_sellToken(address(geist), geistBalance);
}
Expand Down Expand Up @@ -316,32 +318,19 @@ contract StrategyCurveGeist is StrategyCurveBase {
forceHarvestTriggerOnce = false;
}

// Sells our CRV, WFTM, or GEIST for our target token
// Sells our CRV or GEIST for our target token
function _sellToken(address token, uint256 _amount) internal {
if (token == address(wftm)) {
address[] memory tokenPath = new address[](2);
tokenPath[0] = address(wftm);
tokenPath[1] = address(targetToken);
IUniswapV2Router02(router).swapExactTokensForTokens(
_amount,
uint256(0),
tokenPath,
address(this),
block.timestamp
);
} else {
address[] memory tokenPath = new address[](3);
tokenPath[0] = address(token);
tokenPath[1] = address(wftm);
tokenPath[2] = address(targetToken);
IUniswapV2Router02(router).swapExactTokensForTokens(
_amount,
uint256(0),
tokenPath,
address(this),
block.timestamp
);
}
address[] memory tokenPath = new address[](3);
tokenPath[0] = address(token);
tokenPath[1] = address(wftm);
tokenPath[2] = address(targetToken);
IUniswapV2Router02(router).swapExactTokensForTokens(
_amount,
uint256(0),
tokenPath,
address(this),
block.timestamp
);
}

/* ========== KEEP3RS ========== */
Expand Down
120 changes: 8 additions & 112 deletions contracts/interfaces/curve.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,135 +2,31 @@
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 withdraw(uint256) external;

function claim_rewards() external;

function withdraw(uint256) external;
// CRV
function claimable_tokens(address) external returns (uint256);

// Third-party tokens only
function claimable_reward(address, address) external view returns (uint256);
}

interface IGaugeFactory {
function mint(address _gauge) external;
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

0 comments on commit 6d40b6e

Please sign in to comment.