Skip to content

Commit

Permalink
updates following review from strategists and security on #8
Browse files Browse the repository at this point in the history
  • Loading branch information
pata.eth committed May 27, 2022
1 parent 43db300 commit dd4e362
Show file tree
Hide file tree
Showing 21 changed files with 248 additions and 267 deletions.
20 changes: 10 additions & 10 deletions brownie-config.yml
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
# 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: ftm-main-fork

# automatically fetch contract sources from Etherscan
autofetch_sources: True

# require OpenZepplin Contracts
dependencies:
- yearn/[email protected]
- OpenZeppelin/[email protected]
- yearn/[email protected]-1
- OpenZeppelin/[email protected]

# path remapping to support imports from GitHub/NPM
compiler:
solc:
version:
remappings:
- "@yearnvaults=yearn/[email protected]"
- "@openzeppelin=OpenZeppelin/[email protected]"
solc:
version:
remappings:
- "@yearnvaults=yearn/[email protected]-1"
- "@openzeppelin=OpenZeppelin/[email protected]"

reports:
exclude_contracts:
- SafeMath
exclude_contracts:
- SafeMath
66 changes: 33 additions & 33 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 {IGauge, IGaugeFactory, ICurveFi} from "./interfaces/curve.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 {BaseStrategy, StrategyParams} from "@yearnvaults/contracts/BaseStrategy.sol";

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

// Curve stuff
IGauge public constant gauge =
IGauge(0xd4F94D0aaa640BBb72b5EEc2D85F6D114D81a88E); // 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);

// keepCRV stuff
uint256 public keepCRV; // the percentage of CRV we re-lock for boost (in basis points)
Expand Down Expand Up @@ -130,7 +110,23 @@ 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 claimRewards() external onlyVaultManagers {
_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 @@ -215,8 +211,10 @@ 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);
//'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 usdc.
targetToken = address(usdc);
}

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

uint256 crvBalance = crv.balanceOf(address(this));
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 @@ -257,7 +257,7 @@ contract StrategyCurveGeist is StrategyCurveBase {
_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 @@ -374,7 +374,7 @@ contract StrategyCurveGeist 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 fUSDT, but can be set to USDC or DAI as needed by strategist or governance.
// Default is USDC, but can be set to fUSDT or DAI as needed by strategist or governance.
function setOptimal(uint256 _optimal) external onlyAuthorized {
if (_optimal == 0) {
targetToken = address(dai);
Expand Down
125 changes: 9 additions & 116 deletions contracts/interfaces/curve.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,138 +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 claimable_tokens(address) external view returns (uint256);
// CRV
function claimable_tokens(address) external returns (uint256);

function claimable_reward(address _addressToCheck, address _rewardToken)
external
view
returns (uint256);
// Third-party tokens only
function claimable_reward(address, address) external view 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.

6 changes: 4 additions & 2 deletions scripts/deploy.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from pathlib import Path

from brownie import Strategy, accounts, config, network, project, web3
from brownie import StrategyCurveGeist, accounts, config, network, project, web3
from eth_utils import is_checksum_address
import click

Expand Down Expand Up @@ -55,4 +55,6 @@ def main():
if input("Deploy Strategy? y/[N]: ").lower() != "y":
return

strategy = Strategy.deploy(vault, {"from": dev}, publish_source=publish_source)
strategy = StrategyCurveGeist.deploy(
vault, "StrategyCurveGeist", {"from": dev}, publish_source=publish_source
)
Loading

0 comments on commit dd4e362

Please sign in to comment.