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

16slim/ve angle #6

Open
wants to merge 45 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
fe6844d
feat: initial version of central veAngle voter
16slim Jun 6, 2022
7a07c62
fix: changes necessary in tests to make them pass with central veAngle
16slim Jun 6, 2022
0be3adf
feat: lock and increase amount locked
16slim Jun 6, 2022
e35f803
feat: add 2nd harvest
16slim Jun 6, 2022
c863f46
fix: remove percentLock
16slim Jun 8, 2022
3676450
fix: remove percentLock setter
16slim Jun 8, 2022
64c75d7
fix: set governance to ychad in constructors
16slim Jun 8, 2022
649c309
fix: remove .address and rename voter fixtures
16slim Jun 8, 2022
f189c10
fix: remove treasury check for strategy proxy
16slim Jun 8, 2022
f389c7e
feat: add two-step process to set governance
16slim Jun 8, 2022
46571e0
fix: naming convention for proxy, setProxy
16slim Jun 8, 2022
d0140f0
feat: changed prepareMigration logic to convert back to want
16slim Jun 8, 2022
a9ff880
chore: rebase onto most recent security-approved master
charlesndalton Jun 24, 2022
4096176
fix: fix multiple strategies using stablemaster
16slim Jun 28, 2022
31ff372
chore: fix translation errors
16slim Jul 5, 2022
9db840c
fix: remove debugging event
16slim Jul 5, 2022
88f18fd
feat: add whitelister interface to test lock
16slim Jul 7, 2022
618637b
feat: test lock & release veAngle
16slim Jul 7, 2022
15ce260
chore: remove debugging make
16slim Jul 7, 2022
de4174d
fix: remove approveStrategy as it's included in fixture
16slim Jul 7, 2022
5072669
chore: removed unused deposit and approve
16slim Jul 7, 2022
06b0dae
chore: remove unnecessary approve
16slim Jul 7, 2022
aa72c39
fix: change test to check voter proxy instead of treasury
16slim Jul 7, 2022
2435759
feat: add boolean to approve and whitelist voter
16slim Jul 7, 2022
a6aa5d6
fix: fix _withdrawSome()
16slim Jul 7, 2022
cdbe6c4
chore: remove .py tests
16slim Jul 7, 2022
915b8a4
fix: remove unused cursor variable
16slim Jul 11, 2022
dfc900d
chore: rename angle to angleToken
16slim Jul 11, 2022
16f7e42
feat: check allowance function
16slim Jul 15, 2022
432873a
fix: remove token parameter from claimRewards
16slim Jul 15, 2022
8c607ed
chore: rename deposit to stake
16slim Jul 15, 2022
ada3a34
fix: typo in _withdrawSome
16slim Jul 15, 2022
8fb4d14
chore: remove comment and add space
16slim Jul 15, 2022
d7571d9
feat: save gas approving angle from voter
16slim Jul 15, 2022
f4e0c73
chore: rename balanceOf to balanceOfSTakedSanToken
16slim Jul 18, 2022
8c63ff1
feat: add access control to lock() function
16slim Jul 22, 2022
528a4c4
fix: replace fro withdrawAll in strategy
16slim Jul 22, 2022
8ba167e
fix: necessary changes for access control lock to pass
16slim Jul 22, 2022
c848384
feat: Angle rewards stay in voter and not in proxy
16slim Jul 22, 2022
542f347
fix: hardcode unlock time and remove access control to locl
16slim Jul 22, 2022
748466f
fix: include force harvest trigger fix
16slim Aug 2, 2022
5c3038e
chore: remove unused imports
16slim Aug 15, 2022
ea48325
feat: add revert message to safeExecute
16slim Aug 15, 2022
cf81296
feat: clean migration process
16slim Aug 15, 2022
6937fad
feat: include message error in safeExecute
16slim Aug 25, 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
181 changes: 181 additions & 0 deletions src/AngleStrategyVoterProxy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.12;
pragma experimental ABIEncoderV2;

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

import {YearnAngleVoter} from "./YearnAngleVoter.sol";

import "./interfaces/curve/ICurve.sol";
import "./interfaces/Angle/IStableMaster.sol";
import "./interfaces/Angle/IAngleGauge.sol";
import "./interfaces/Uniswap/IUniV2.sol";

library SafeVoter {
function safeExecute(
YearnAngleVoter voter,
address to,
uint256 value,
bytes memory data
) internal {
(bool success, bytes memory result) = voter.execute(to, value, data);
require(success, string(result));
}
}

contract AngleStrategyVoterProxy {
using SafeVoter for YearnAngleVoter;
using SafeERC20 for IERC20;
using Address for address;

YearnAngleVoter public yearnAngleVoter;
address public constant angleToken = address(0x31429d1856aD1377A8A0079410B297e1a9e214c2);

uint256 public constant UNLOCK_TIME = 4 * 365 * 24 * 60 * 60;

// gauge => strategies
mapping(address => address) public strategies;
mapping(address => bool) public voters;
address public governance;

constructor(address _voter) public {
governance = address(0xFEB4acf3df3cDEA7399794D0869ef76A6EfAff52);
yearnAngleVoter = YearnAngleVoter(_voter);
}

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

function approveStrategy(address _gauge, address _strategy) external {
require(msg.sender == governance, "!governance");
strategies[_gauge] = _strategy;
}

function revokeStrategy(address _gauge) external {
require(msg.sender == governance, "!governance");
strategies[_gauge] = address(0);
}

function approveVoter(address _voter) external {
require(msg.sender == governance, "!governance");
voters[_voter] = true;
}
charlesndalton marked this conversation as resolved.
Show resolved Hide resolved

function revokeVoter(address _voter) external {
require(msg.sender == governance, "!governance");
voters[_voter] = false;
}

function lock(uint256 amount) external {
if (amount > 0 && amount <= IERC20(angleToken).balanceOf(address(yearnAngleVoter))) {
yearnAngleVoter.createLock(amount, block.timestamp + UNLOCK_TIME);
}
}

function increaseAmount(uint256 amount) external {
if (amount > 0 && amount <= IERC20(angleToken).balanceOf(address(yearnAngleVoter))) {
yearnAngleVoter.increaseAmount(amount);
}
}

function vote(address _gauge, uint256 _amount) public {
require(voters[msg.sender], "!voter");
yearnAngleVoter.safeExecute(_gauge, 0, abi.encodeWithSignature("vote_for_gauge_weights(address,uint256)", _gauge, _amount));
}

function withdraw(
address _gauge,
address _token,
uint256 _amount
) public returns (uint256) {
require(strategies[_gauge] == msg.sender, "!strategy");
uint256 _balance = IERC20(_token).balanceOf(address(yearnAngleVoter));
yearnAngleVoter.safeExecute(_gauge, 0, abi.encodeWithSignature("withdraw(uint256)", _amount));
_balance = IERC20(_token).balanceOf(address(yearnAngleVoter)) - _balance;
yearnAngleVoter.safeExecute(_token, 0, abi.encodeWithSignature("transfer(address,uint256)", msg.sender, _balance));
charlesndalton marked this conversation as resolved.
Show resolved Hide resolved
return _balance;
}

function withdrawFromStableMaster(address stableMaster, uint256 amount,
address poolManager, address token, address gauge) external {
16slim marked this conversation as resolved.
Show resolved Hide resolved
require(strategies[gauge] == msg.sender, "!strategy");

IERC20(token).safeTransfer(address(yearnAngleVoter), amount);

yearnAngleVoter.safeExecute(stableMaster, 0, abi.encodeWithSignature(
"withdraw(uint256,address,address,address)",
amount,
address(yearnAngleVoter),
msg.sender,
poolManager
));
}

function balanceOfStakedSanToken(address _gauge) public view returns (uint256) {
return IERC20(_gauge).balanceOf(address(yearnAngleVoter));
}

function withdrawAll(address _gauge, address _token) external returns (uint256) {
charlesndalton marked this conversation as resolved.
Show resolved Hide resolved
require(strategies[_gauge] == msg.sender, "!strategy");
return withdraw(_gauge, _token, balanceOfStakedSanToken(_gauge));
}

function stake(address gauge, uint256 amount, address token) external {
require(strategies[gauge] == msg.sender, "!strategy");

_checkAllowance(token, gauge, amount);

yearnAngleVoter.safeExecute(gauge, 0, abi.encodeWithSignature(
"deposit(uint256)",
amount
));
}

function depositToStableMaster(address stableMaster, uint256 amount,
address poolManager, address token, address gauge) external {
require(strategies[gauge] == msg.sender, "!strategy");

IERC20(token).safeTransfer(address(yearnAngleVoter), amount);

_checkAllowance(token, stableMaster, amount);

yearnAngleVoter.safeExecute(stableMaster, 0, abi.encodeWithSignature(
"deposit(uint256,address,address)",
amount,
address(yearnAngleVoter),
poolManager
));
}

function claimRewards(address _gauge) external {
require(strategies[_gauge] == msg.sender, "!strategy");
yearnAngleVoter.safeExecute(
_gauge,
0,
abi.encodeWithSelector(
IAngleGauge.claim_rewards.selector
)
);
address _token = address(angleToken);
yearnAngleVoter.safeExecute(_token, 0, abi.encodeWithSignature("transfer(address,uint256)", msg.sender, IERC20(_token).balanceOf(address(yearnAngleVoter))));
}

function balanceOfSanToken(address sanToken) public view returns (uint256) {
return IERC20(sanToken).balanceOf(address(yearnAngleVoter));
}

function _checkAllowance(
address _token,
address _contract,
uint256 _amount
) internal {
if (IERC20(_token).allowance(address(yearnAngleVoter), _contract) < _amount) {
yearnAngleVoter.safeExecute(_token, 0, abi.encodeWithSignature("approve(address,uint256)", _contract, 0));
yearnAngleVoter.safeExecute(_token, 0, abi.encodeWithSignature("approve(address,uint256)", _contract, _amount));
}
}
}
Loading