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
15 changes: 15 additions & 0 deletions contracts/interfaces/curve.sol
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ interface ICurveFi_3 {
function add_liquidity(uint256[3] calldata amounts, uint256 min_mint_amount)
external;

function add_liquidity(uint256[3] calldata amounts, uint256 min_mint_amount, bool _use_underlying)
external returns (uint256);

function remove_liquidity_imbalance(
uint256[3] calldata amounts,
uint256 max_burn_amount
Expand Down Expand Up @@ -79,6 +82,14 @@ interface ICurveFi_4 {
function balances(int128) external view returns (uint256);
}

interface ICurveFi_5 {
function add_liquidity(
uint256[] calldata _amounts,
uint256 _min_mint_amount,
bool _use_underlying
) external returns (uint256);
}

interface ICurveZap_4 {
function add_liquidity(
uint256[4] calldata uamounts,
Expand Down Expand Up @@ -151,6 +162,10 @@ interface ICurveGauge {
function claimable_reward(address, address) external view returns (uint256);

function integrate_fraction(address arg0) external view returns (uint256);

function bridge(address _token) external returns (bool);

function add_liquidity(uint256[] calldata _amounts, uint256 _min_mint_amount) external returns (uint256);
}

interface ICurveMintr {
Expand Down
131 changes: 131 additions & 0 deletions contracts/snowglobes/curve/snowglobe-crv-aave.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// https://github.com/iearn-finance/vaults/blob/master/contracts/vaults/yVault.sol

pragma solidity ^0.6.7;

import "../../interfaces/controller.sol";

import "../../lib/erc20.sol";
import "../../lib/safe-math.sol";

contract SnowGlobeCrvAave is ERC20 {
using SafeERC20 for IERC20;
using Address for address;
using SafeMath for uint256;

IERC20 public token;

uint256 public min = 9500;
uint256 public constant max = 10000;

address public governance;
address public timelock;
address public controller;

constructor(address _token, address _governance, address _timelock, address _controller)
public
ERC20(
string(abi.encodePacked("freezing ", ERC20(_token).name())),
string(abi.encodePacked("s", ERC20(_token).symbol()))
)
{
_setupDecimals(ERC20(_token).decimals());
token = IERC20(_token);
governance = _governance;
timelock = _timelock;
controller = _controller;
}

function balance() public view returns (uint256) {
return
token.balanceOf(address(this)).add(
IController(controller).balanceOf(address(token))
);
}

function setMin(uint256 _min) external {
require(msg.sender == governance, "!governance");
require(_min <= max, "numerator cannot be greater than denominator");
min = _min;
}

function setGovernance(address _governance) public {
require(msg.sender == governance, "!governance");
governance = _governance;
}

function setTimelock(address _timelock) public {
require(msg.sender == timelock, "!timelock");
timelock = _timelock;
}

function setController(address _controller) public {
require(msg.sender == timelock, "!timelock");
controller = _controller;
}

// Custom logic in here for how much the globes allows to be borrowed
// Sets minimum required on-hand to keep small withdrawals cheap
function available() public view returns (uint256) {
return token.balanceOf(address(this)).mul(min).div(max);
}

function earn() public {
uint256 _bal = available();
token.safeTransfer(controller, _bal);
IController(controller).earn(address(token), _bal);
}

function depositAll() external {
deposit(token.balanceOf(msg.sender));
}

function deposit(uint256 _amount) public {
uint256 _pool = balance();
uint256 _before = token.balanceOf(address(this));
token.safeTransferFrom(msg.sender, address(this), _amount);
uint256 _after = token.balanceOf(address(this));
_amount = _after.sub(_before); // Additional check for deflationary tokens
uint256 shares = 0;
if (totalSupply() == 0) {
shares = _amount;
} else {
shares = (_amount.mul(totalSupply())).div(_pool);
}
_mint(msg.sender, shares);
}

function withdrawAll() external {
withdraw(balanceOf(msg.sender));
}

// Used to swap any borrowed reserve over the debt limit to liquidate to 'token'
function harvest(address reserve, uint256 amount) external {
require(msg.sender == controller, "!controller");
require(reserve != address(token), "token");
IERC20(reserve).safeTransfer(controller, amount);
}

// No rebalance implementation for lower fees and faster swaps
function withdraw(uint256 _shares) public {
uint256 r = (balance().mul(_shares)).div(totalSupply());
_burn(msg.sender, _shares);

// Check balance
uint256 b = token.balanceOf(address(this));
if (b < r) {
uint256 _withdraw = r.sub(b);
IController(controller).withdraw(address(token), _withdraw);
uint256 _after = token.balanceOf(address(this));
uint256 _diff = _after.sub(b);
if (_diff < _withdraw) {
r = b.add(_diff);
}
}

token.safeTransfer(msg.sender, r);
}

function getRatio() public view returns (uint256) {
return balance().mul(1e18).div(totalSupply());
}
}
119 changes: 119 additions & 0 deletions contracts/strategies/bases/strategy-crv-base.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.7;

import "../strategy-joe-base.sol";
import "../../interfaces/curve.sol";
import "../../interfaces/wavax.sol";
import "../../interfaces/aave.sol";

abstract contract StrategyCrvBase is StrategyJoeBase {
address public gauge = 0x5B5CFE992AdAC0C9D48E05854B2d91C73a003858;
address public constant crv = 0x47536F17F4fF30e64A96a7555826b8f9e66ec468;

address public constant lendingPool = 0x4F01AeD16D97E3aB5ab2B501154DC9bb0F1A5A2C;
uint16 public constant REFERRAL_CODE = 0xaa;

address public liquidity;

// Underlying tokens in the pool
address public token1;
address public token2;
address public token3;

constructor(
address _token1,
address _token2,
address _token3,
address _liquidity,
address _want,
address _governance,
address _strategist,
address _controller,
address _timelock
)
public StrategyJoeBase(
_want,
_governance,
_strategist,
_controller,
_timelock
)
{
liquidity = _liquidity;
token1 = _token1;
token2 = _token2;
token3 = _token3;
}

// **** Getters ****

function balanceOfPool() public override view returns (uint256) {
uint256 amount = ICurveGauge(gauge).balanceOf(address(this));
return amount;
}

function getHarvestable() external view returns (uint256, uint256) {
uint256 pendingCrv = ICurveGauge(gauge).claimable_reward(address(this), crv);
uint256 pendingWavax = ICurveGauge(gauge).claimable_reward(address(this), wavax);
return (pendingCrv, pendingWavax);
}


// **** State Mutation functions ****

function deposit() public override {
uint256 _want = IERC20(want).balanceOf(address(this));
if (_want > 0) {
IERC20(want).safeApprove(gauge, 0);
IERC20(want).safeApprove(gauge, _want);
ICurveGauge(gauge).deposit(_want);
}
}

function _withdrawSome(uint256 _amount)
internal
override
returns (uint256)
{
ICurveGauge(gauge).withdraw(_amount, true);
return _amount;
}

// **** This function checks the balances of the underlying tokens in **** //
// **** the pool and returns the one with the least liquidity present **** //
function getMostPremium()
public
view
returns (address, uint256)
{
uint256[] memory balances = new uint256[](3);
balances[0] = ICurveFi_3(liquidity).balances(0);
balances[1] = ICurveFi_3(liquidity).balances(1);
balances[2] = ICurveFi_3(liquidity).balances(2);

if (
balances[0] < balances[1] &&
balances[0] < balances[2]
) {
return (token1, 0);
}

if (
balances[1] < balances[0] &&
balances[1] < balances[2]
) {
return (token2, 1);
}

if (
balances[2] < balances[0] &&
balances[2] < balances[1]
) {
return (token3, 2);
}

// If they're somehow equal, we just want any underlying token
return (token1, 0);
}

}
Loading