mirror of
https://github.com/Instadapp/aave-protocol-v2.git
synced 2024-07-29 21:47:30 +00:00
185 lines
5.5 KiB
Solidity
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;
|
|
}
|
|
}
|