aave-protocol-v2/contracts/adapters/rewards/CurveTreasury.sol

185 lines
5.5 KiB
Solidity

// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.12;
import {IERC20} from '../../dependencies/openzeppelin/contracts/IERC20.sol';
import {SafeERC20} from '../../dependencies/openzeppelin/contracts/SafeERC20.sol';
import {ICurveGauge, ICurveGaugeView} from '../interfaces/curve/ICurveGauge.sol';
import {IVotingEscrow} from '../interfaces/curve/IVotingEscrow.sol';
import {
VersionedInitializable
} from '../../protocol/libraries/aave-upgradeability/VersionedInitializable.sol';
import {ICurveFeeDistributor} from '../interfaces/curve/ICurveFeeDistributor.sol';
/**
* @title Curve Treasury that holds Curve LP and Gauge tokens
* @notice The treasury holds Curve assets like LP or Gauge tokens and can lock veCRV for boosting Curve yields
* @author Aave
*/
contract CurveTreasury is VersionedInitializable {
using SafeERC20 for IERC20;
address immutable VOTING_ESCROW;
address immutable CRV_TOKEN;
address immutable FEE_DISTRIBUTOR;
address private _owner;
uint256 public constant TREASURY_REVISION = 0x1;
mapping(address => mapping(address => bool)) internal _entityTokenWhitelist;
mapping(address => mapping(address => address)) internal _entityTokenGauge;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor(
address _votingEscrow,
address _crvToken,
address _curveFeeDistributor
) public {
VOTING_ESCROW = _votingEscrow;
CRV_TOKEN = _crvToken;
FEE_DISTRIBUTOR = _curveFeeDistributor;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(_owner == msg.sender, 'Ownable: caller is not the owner');
_;
}
modifier onlyWhitelistedEntity(address token) {
require(_entityTokenWhitelist[msg.sender][token] == true, 'ENTITY_NOT_WHITELISTED');
_;
}
function initialize(
address[] calldata entities,
address[] calldata tokens,
address[] calldata gauges,
address owner
) external virtual initializer {
_owner = owner;
bool[] memory whitelisted = new bool[](entities.length);
_setWhitelist(entities, tokens, gauges, whitelisted);
}
function getRevision() internal pure virtual override returns (uint256) {
return TREASURY_REVISION;
}
function deposit(
address token,
uint256 amount,
bool useGauge
) external onlyWhitelistedEntity(token) {
IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
if (useGauge && _entityTokenGauge[msg.sender][token] != address(0)) {
stakeGauge(_entityTokenGauge[msg.sender][token], amount);
}
}
function withdraw(
address token,
uint256 amount,
bool useGauge
) external onlyWhitelistedEntity(token) {
if (useGauge && _entityTokenGauge[msg.sender][token] != address(0)) {
unstakeGauge(_entityTokenGauge[msg.sender][token], amount);
}
IERC20(token).safeTransfer(msg.sender, amount);
}
function stakeGauge(address gauge, uint256 amount) internal {
ICurveGauge(gauge).deposit(amount);
}
function unstakeGauge(address gauge, uint256 amount) internal {
ICurveGauge(gauge).withdraw(amount);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() external view returns (address) {
return _owner;
}
/** Owner methods */
function approve(
address token,
address to,
uint256 amount
) external onlyOwner {
IERC20(token).safeApprove(to, amount);
}
function transferFrom(
address token,
address from,
address to,
uint256 amount
) external onlyOwner {
IERC20(token).safeTransferFrom(from, to, amount);
}
function setWhitelist(
address[] calldata entities,
address[] calldata tokens,
address[] calldata gauges,
bool[] memory whitelisted
) external onlyOwner {
_setWhitelist(entities, tokens, gauges, whitelisted);
}
function _setWhitelist(
address[] calldata entities,
address[] calldata tokens,
address[] calldata gauges,
bool[] memory whitelisted
) internal {
for (uint256 e; e < entities.length; e++) {
_entityTokenWhitelist[entities[e]][tokens[e]] = whitelisted[e];
IERC20(tokens[e]).safeApprove(entities[e], type(uint256).max);
if (gauges[e] != address(0)) {
IERC20(tokens[e]).safeApprove(gauges[e], type(uint256).max);
_entityTokenGauge[entities[e]][tokens[e]] = gauges[e];
}
}
}
function claimCurveFees() external onlyOwner {
ICurveFeeDistributor(FEE_DISTRIBUTOR).claim();
}
/** Owner methods related with veCRV to interact with Voting Escrow Curve contract */
function lockCrv(uint256 amount, uint256 unlockTime) external onlyOwner {
IERC20(CRV_TOKEN).safeApprove(VOTING_ESCROW, amount);
IVotingEscrow(VOTING_ESCROW).create_lock(amount, unlockTime);
}
function unlockCrv(uint256 amount, uint256 unlockTime) external onlyOwner {
IVotingEscrow(VOTING_ESCROW).withdraw();
}
function increaseLockedCrv(uint256 amount) external onlyOwner {
IERC20(CRV_TOKEN).safeApprove(VOTING_ESCROW, amount);
IVotingEscrow(VOTING_ESCROW).increase_amount(amount);
}
function increaseUnlockTimeCrv(uint256 unlockTime) external onlyOwner {
IVotingEscrow(VOTING_ESCROW).increase_unlock_time(unlockTime);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) external onlyOwner {
require(newOwner != address(0), 'Ownable: new owner is the zero address');
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}