Contract Source Code:
//SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
interface IAdmin {
function setAdmin(address _admin) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
import "./IVault.sol";
interface IGlpManager {
function glp() external view returns (address);
function usdg() external view returns (address);
function vault() external view returns (IVault);
function cooldownDuration() external returns (uint256);
function getAumInUsdg(bool maximise) external view returns (uint256);
function lastAddedAt(address _account) external returns (uint256);
function addLiquidity(address _token, uint256 _amount, uint256 _minUsdg, uint256 _minGlp) external returns (uint256);
function addLiquidityForAccount(address _fundingAccount, address _account, address _token, uint256 _amount, uint256 _minUsdg, uint256 _minGlp) external returns (uint256);
function removeLiquidity(address _tokenOut, uint256 _glpAmount, uint256 _minOut, address _receiver) external returns (uint256);
function removeLiquidityForAccount(address _account, address _tokenOut, uint256 _glpAmount, uint256 _minOut, address _receiver) external returns (uint256);
function setShortsTrackerAveragePriceWeight(uint256 _shortsTrackerAveragePriceWeight) external;
function setCooldownDuration(uint256 _cooldownDuration) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
import "./IVaultUtils.sol";
interface IVault {
function isInitialized() external view returns (bool);
function isSwapEnabled() external view returns (bool);
function isLeverageEnabled() external view returns (bool);
function setVaultUtils(IVaultUtils _vaultUtils) external;
function setError(uint256 _errorCode, string calldata _error) external;
function router() external view returns (address);
function usdg() external view returns (address);
function gov() external view returns (address);
function whitelistedTokenCount() external view returns (uint256);
function maxLeverage() external view returns (uint256);
function minProfitTime() external view returns (uint256);
function hasDynamicFees() external view returns (bool);
function fundingInterval() external view returns (uint256);
function totalTokenWeights() external view returns (uint256);
function getTargetUsdgAmount(address _token) external view returns (uint256);
function inManagerMode() external view returns (bool);
function inPrivateLiquidationMode() external view returns (bool);
function maxGasPrice() external view returns (uint256);
function approvedRouters(address _account, address _router) external view returns (bool);
function isLiquidator(address _account) external view returns (bool);
function isManager(address _account) external view returns (bool);
function minProfitBasisPoints(address _token) external view returns (uint256);
function tokenBalances(address _token) external view returns (uint256);
function lastFundingTimes(address _token) external view returns (uint256);
function setMaxLeverage(uint256 _maxLeverage) external;
function setInManagerMode(bool _inManagerMode) external;
function setManager(address _manager, bool _isManager) external;
function setIsSwapEnabled(bool _isSwapEnabled) external;
function setIsLeverageEnabled(bool _isLeverageEnabled) external;
function setMaxGasPrice(uint256 _maxGasPrice) external;
function setUsdgAmount(address _token, uint256 _amount) external;
function setBufferAmount(address _token, uint256 _amount) external;
function setMaxGlobalShortSize(address _token, uint256 _amount) external;
function setInPrivateLiquidationMode(bool _inPrivateLiquidationMode) external;
function setLiquidator(address _liquidator, bool _isActive) external;
function setFundingRate(uint256 _fundingInterval, uint256 _fundingRateFactor, uint256 _stableFundingRateFactor) external;
function setFees(
uint256 _taxBasisPoints,
uint256 _stableTaxBasisPoints,
uint256 _mintBurnFeeBasisPoints,
uint256 _swapFeeBasisPoints,
uint256 _stableSwapFeeBasisPoints,
uint256 _marginFeeBasisPoints,
uint256 _liquidationFeeUsd,
uint256 _minProfitTime,
bool _hasDynamicFees
) external;
function setTokenConfig(
address _token,
uint256 _tokenDecimals,
uint256 _redemptionBps,
uint256 _minProfitBps,
uint256 _maxUsdgAmount,
bool _isStable,
bool _isShortable
) external;
function setPriceFeed(address _priceFeed) external;
function withdrawFees(address _token, address _receiver) external returns (uint256);
function directPoolDeposit(address _token) external;
function buyUSDG(address _token, address _receiver) external returns (uint256);
function sellUSDG(address _token, address _receiver) external returns (uint256);
function swap(address _tokenIn, address _tokenOut, address _receiver) external returns (uint256);
function increasePosition(address _account, address _collateralToken, address _indexToken, uint256 _sizeDelta, bool _isLong) external;
function decreasePosition(address _account, address _collateralToken, address _indexToken, uint256 _collateralDelta, uint256 _sizeDelta, bool _isLong, address _receiver) external returns (uint256);
function validateLiquidation(address _account, address _collateralToken, address _indexToken, bool _isLong, bool _raise) external view returns (uint256, uint256);
function liquidatePosition(address _account, address _collateralToken, address _indexToken, bool _isLong, address _feeReceiver) external;
function tokenToUsdMin(address _token, uint256 _tokenAmount) external view returns (uint256);
function priceFeed() external view returns (address);
function fundingRateFactor() external view returns (uint256);
function stableFundingRateFactor() external view returns (uint256);
function cumulativeFundingRates(address _token) external view returns (uint256);
function getNextFundingRate(address _token) external view returns (uint256);
function getFeeBasisPoints(address _token, uint256 _usdgDelta, uint256 _feeBasisPoints, uint256 _taxBasisPoints, bool _increment) external view returns (uint256);
function liquidationFeeUsd() external view returns (uint256);
function taxBasisPoints() external view returns (uint256);
function stableTaxBasisPoints() external view returns (uint256);
function mintBurnFeeBasisPoints() external view returns (uint256);
function swapFeeBasisPoints() external view returns (uint256);
function stableSwapFeeBasisPoints() external view returns (uint256);
function marginFeeBasisPoints() external view returns (uint256);
function allWhitelistedTokensLength() external view returns (uint256);
function allWhitelistedTokens(uint256) external view returns (address);
function whitelistedTokens(address _token) external view returns (bool);
function stableTokens(address _token) external view returns (bool);
function shortableTokens(address _token) external view returns (bool);
function feeReserves(address _token) external view returns (uint256);
function globalShortSizes(address _token) external view returns (uint256);
function globalShortAveragePrices(address _token) external view returns (uint256);
function maxGlobalShortSizes(address _token) external view returns (uint256);
function tokenDecimals(address _token) external view returns (uint256);
function tokenWeights(address _token) external view returns (uint256);
function guaranteedUsd(address _token) external view returns (uint256);
function poolAmounts(address _token) external view returns (uint256);
function bufferAmounts(address _token) external view returns (uint256);
function reservedAmounts(address _token) external view returns (uint256);
function usdgAmounts(address _token) external view returns (uint256);
function maxUsdgAmounts(address _token) external view returns (uint256);
function getRedemptionAmount(address _token, uint256 _usdgAmount) external view returns (uint256);
function getMaxPrice(address _token) external view returns (uint256);
function getMinPrice(address _token) external view returns (uint256);
function getDelta(address _indexToken, uint256 _size, uint256 _averagePrice, bool _isLong, uint256 _lastIncreasedTime) external view returns (bool, uint256);
function getPosition(address _account, address _collateralToken, address _indexToken, bool _isLong) external view returns (uint256, uint256, uint256, uint256, uint256, uint256, bool, uint256);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
interface IVaultUtils {
function updateCumulativeFundingRate(address _collateralToken, address _indexToken) external returns (bool);
function validateIncreasePosition(address _account, address _collateralToken, address _indexToken, uint256 _sizeDelta, bool _isLong) external view;
function validateDecreasePosition(address _account, address _collateralToken, address _indexToken, uint256 _collateralDelta, uint256 _sizeDelta, bool _isLong, address _receiver) external view;
function validateLiquidation(address _account, address _collateralToken, address _indexToken, bool _isLong, bool _raise) external view returns (uint256, uint256);
function getEntryFundingRate(address _collateralToken, address _indexToken, bool _isLong) external view returns (uint256);
function getPositionFee(address _account, address _collateralToken, address _indexToken, bool _isLong, uint256 _sizeDelta) external view returns (uint256);
function getFundingFee(address _account, address _collateralToken, address _indexToken, bool _isLong, uint256 _size, uint256 _entryFundingRate) external view returns (uint256);
function getBuyUsdgFeeBasisPoints(address _token, uint256 _usdgAmount) external view returns (uint256);
function getSellUsdgFeeBasisPoints(address _token, uint256 _usdgAmount) external view returns (uint256);
function getSwapFeeBasisPoints(address _tokenIn, address _tokenOut, uint256 _usdgAmount) external view returns (uint256);
function getFeeBasisPoints(address _token, uint256 _usdgDelta, uint256 _feeBasisPoints, uint256 _taxBasisPoints, bool _increment) external view returns (uint256);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
interface IHandlerTarget {
function isHandler(address _account) external returns (bool);
function setHandler(address _handler, bool _isActive) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
interface ITimelock {
function marginFeeBasisPoints() external returns (uint256);
function setAdmin(address _admin) external;
function enableLeverage(address _vault) external;
function disableLeverage(address _vault) external;
function setIsLeverageEnabled(address _vault, bool _isLeverageEnabled) external;
function signalSetGov(address _target, address _gov) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
interface ITimelockTarget {
function setGov(address _gov) external;
function withdrawToken(address _token, address _account, uint256 _amount) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
import "./interfaces/ITimelockTarget.sol";
import "./interfaces/ITimelock.sol";
import "./interfaces/IHandlerTarget.sol";
import "../access/interfaces/IAdmin.sol";
import "../core/interfaces/IVault.sol";
import "../core/interfaces/IVaultUtils.sol";
import "../core/interfaces/IGlpManager.sol";
import "../referrals/interfaces/IReferralStorage.sol";
import "../tokens/interfaces/IYieldToken.sol";
import "../tokens/interfaces/IBaseToken.sol";
import "../tokens/interfaces/IMintable.sol";
import "../tokens/interfaces/IUSDG.sol";
import "../staking/interfaces/IVester.sol";
import "../staking/interfaces/IRewardRouterV2.sol";
import "../libraries/math/SafeMath.sol";
import "../libraries/token/IERC20.sol";
contract Timelock is ITimelock {
using SafeMath for uint256;
uint256 public constant PRICE_PRECISION = 10 ** 30;
uint256 public constant MAX_BUFFER = 5 days;
uint256 public constant MAX_FUNDING_RATE_FACTOR = 200; // 0.02%
uint256 public constant MAX_LEVERAGE_VALIDATION = 500000; // 50x
uint256 public buffer;
address public admin;
address public tokenManager;
address public mintReceiver;
address public glpManager;
address public rewardRouter;
uint256 public maxTokenSupply;
uint256 public override marginFeeBasisPoints;
uint256 public maxMarginFeeBasisPoints;
bool public shouldToggleIsLeverageEnabled;
mapping (bytes32 => uint256) public pendingActions;
mapping (address => bool) public isHandler;
mapping (address => bool) public isKeeper;
event SignalPendingAction(bytes32 action);
event SignalApprove(address token, address spender, uint256 amount, bytes32 action);
event SignalWithdrawToken(address target, address token, address receiver, uint256 amount, bytes32 action);
event SignalMint(address token, address receiver, uint256 amount, bytes32 action);
event SignalSetGov(address target, address gov, bytes32 action);
event SignalSetHandler(address target, address handler, bool isActive, bytes32 action);
event SignalSetPriceFeed(address vault, address priceFeed, bytes32 action);
event SignalRedeemUsdg(address vault, address token, uint256 amount);
event SignalVaultSetTokenConfig(
address vault,
address token,
uint256 tokenDecimals,
uint256 tokenWeight,
uint256 minProfitBps,
uint256 maxUsdgAmount,
bool isStable,
bool isShortable
);
event ClearAction(bytes32 action);
modifier onlyAdmin() {
require(msg.sender == admin, "Timelock: forbidden");
_;
}
modifier onlyHandlerAndAbove() {
require(msg.sender == admin || isHandler[msg.sender], "Timelock: forbidden");
_;
}
modifier onlyKeeperAndAbove() {
require(msg.sender == admin || isHandler[msg.sender] || isKeeper[msg.sender], "Timelock: forbidden");
_;
}
modifier onlyTokenManager() {
require(msg.sender == tokenManager, "Timelock: forbidden");
_;
}
constructor(
address _admin,
uint256 _buffer,
address _tokenManager,
address _mintReceiver,
address _glpManager,
address _rewardRouter,
uint256 _maxTokenSupply,
uint256 _marginFeeBasisPoints,
uint256 _maxMarginFeeBasisPoints
) public {
require(_buffer <= MAX_BUFFER, "Timelock: invalid _buffer");
admin = _admin;
buffer = _buffer;
tokenManager = _tokenManager;
mintReceiver = _mintReceiver;
glpManager = _glpManager;
rewardRouter = _rewardRouter;
maxTokenSupply = _maxTokenSupply;
marginFeeBasisPoints = _marginFeeBasisPoints;
maxMarginFeeBasisPoints = _maxMarginFeeBasisPoints;
}
function setAdmin(address _admin) external override onlyTokenManager {
admin = _admin;
}
function setExternalAdmin(address _target, address _admin) external onlyAdmin {
require(_target != address(this), "Timelock: invalid _target");
IAdmin(_target).setAdmin(_admin);
}
function setContractHandler(address _handler, bool _isActive) external onlyAdmin {
isHandler[_handler] = _isActive;
}
function initGlpManager() external onlyAdmin {
IGlpManager _glpManager = IGlpManager(glpManager);
IMintable glp = IMintable(_glpManager.glp());
glp.setMinter(glpManager, true);
IUSDG usdg = IUSDG(_glpManager.usdg());
usdg.addVault(glpManager);
IVault vault = _glpManager.vault();
vault.setManager(glpManager, true);
}
function initRewardRouter() external onlyAdmin {
IRewardRouterV2 _rewardRouter = IRewardRouterV2(rewardRouter);
IHandlerTarget(_rewardRouter.feeGlpTracker()).setHandler(rewardRouter, true);
IHandlerTarget(_rewardRouter.stakedGlpTracker()).setHandler(rewardRouter, true);
IHandlerTarget(glpManager).setHandler(rewardRouter, true);
}
function setKeeper(address _keeper, bool _isActive) external onlyAdmin {
isKeeper[_keeper] = _isActive;
}
function setBuffer(uint256 _buffer) external onlyAdmin {
require(_buffer <= MAX_BUFFER, "Timelock: invalid _buffer");
// require(_buffer > buffer, "Timelock: buffer cannot be decreased");
buffer = _buffer;
}
function setMaxLeverage(address _vault, uint256 _maxLeverage) external onlyAdmin {
require(_maxLeverage > MAX_LEVERAGE_VALIDATION, "Timelock: invalid _maxLeverage");
IVault(_vault).setMaxLeverage(_maxLeverage);
}
function setFundingRate(address _vault, uint256 _fundingInterval, uint256 _fundingRateFactor, uint256 _stableFundingRateFactor) external onlyKeeperAndAbove {
require(_fundingRateFactor < MAX_FUNDING_RATE_FACTOR, "Timelock: invalid _fundingRateFactor");
require(_stableFundingRateFactor < MAX_FUNDING_RATE_FACTOR, "Timelock: invalid _stableFundingRateFactor");
IVault(_vault).setFundingRate(_fundingInterval, _fundingRateFactor, _stableFundingRateFactor);
}
function setShouldToggleIsLeverageEnabled(bool _shouldToggleIsLeverageEnabled) external onlyHandlerAndAbove {
shouldToggleIsLeverageEnabled = _shouldToggleIsLeverageEnabled;
}
function setMarginFeeBasisPoints(uint256 _marginFeeBasisPoints, uint256 _maxMarginFeeBasisPoints) external onlyHandlerAndAbove {
marginFeeBasisPoints = _marginFeeBasisPoints;
maxMarginFeeBasisPoints = _maxMarginFeeBasisPoints;
}
function setSwapFees(
address _vault,
uint256 _taxBasisPoints,
uint256 _stableTaxBasisPoints,
uint256 _mintBurnFeeBasisPoints,
uint256 _swapFeeBasisPoints,
uint256 _stableSwapFeeBasisPoints
) external onlyKeeperAndAbove {
IVault vault = IVault(_vault);
vault.setFees(
_taxBasisPoints,
_stableTaxBasisPoints,
_mintBurnFeeBasisPoints,
_swapFeeBasisPoints,
_stableSwapFeeBasisPoints,
maxMarginFeeBasisPoints,
vault.liquidationFeeUsd(),
vault.minProfitTime(),
vault.hasDynamicFees()
);
}
// assign _marginFeeBasisPoints to this.marginFeeBasisPoints
// because enableLeverage would update Vault.marginFeeBasisPoints to this.marginFeeBasisPoints
// and disableLeverage would reset the Vault.marginFeeBasisPoints to this.maxMarginFeeBasisPoints
function setFees(
address _vault,
uint256 _taxBasisPoints,
uint256 _stableTaxBasisPoints,
uint256 _mintBurnFeeBasisPoints,
uint256 _swapFeeBasisPoints,
uint256 _stableSwapFeeBasisPoints,
uint256 _marginFeeBasisPoints,
uint256 _liquidationFeeUsd,
uint256 _minProfitTime,
bool _hasDynamicFees
) external onlyKeeperAndAbove {
marginFeeBasisPoints = _marginFeeBasisPoints;
IVault(_vault).setFees(
_taxBasisPoints,
_stableTaxBasisPoints,
_mintBurnFeeBasisPoints,
_swapFeeBasisPoints,
_stableSwapFeeBasisPoints,
maxMarginFeeBasisPoints,
_liquidationFeeUsd,
_minProfitTime,
_hasDynamicFees
);
}
function enableLeverage(address _vault) external override onlyHandlerAndAbove {
IVault vault = IVault(_vault);
if (shouldToggleIsLeverageEnabled) {
vault.setIsLeverageEnabled(true);
}
vault.setFees(
vault.taxBasisPoints(),
vault.stableTaxBasisPoints(),
vault.mintBurnFeeBasisPoints(),
vault.swapFeeBasisPoints(),
vault.stableSwapFeeBasisPoints(),
marginFeeBasisPoints,
vault.liquidationFeeUsd(),
vault.minProfitTime(),
vault.hasDynamicFees()
);
}
function disableLeverage(address _vault) external override onlyHandlerAndAbove {
IVault vault = IVault(_vault);
if (shouldToggleIsLeverageEnabled) {
vault.setIsLeverageEnabled(false);
}
vault.setFees(
vault.taxBasisPoints(),
vault.stableTaxBasisPoints(),
vault.mintBurnFeeBasisPoints(),
vault.swapFeeBasisPoints(),
vault.stableSwapFeeBasisPoints(),
maxMarginFeeBasisPoints, // marginFeeBasisPoints
vault.liquidationFeeUsd(),
vault.minProfitTime(),
vault.hasDynamicFees()
);
}
function setIsLeverageEnabled(address _vault, bool _isLeverageEnabled) external override onlyHandlerAndAbove {
IVault(_vault).setIsLeverageEnabled(_isLeverageEnabled);
}
function setTokenConfig(
address _vault,
address _token,
uint256 _tokenWeight,
uint256 _minProfitBps,
uint256 _maxUsdgAmount,
uint256 _bufferAmount,
uint256 _usdgAmount
) external onlyKeeperAndAbove {
require(_minProfitBps <= 500, "Timelock: invalid _minProfitBps");
IVault vault = IVault(_vault);
require(vault.whitelistedTokens(_token), "Timelock: token not yet whitelisted");
uint256 tokenDecimals = vault.tokenDecimals(_token);
bool isStable = vault.stableTokens(_token);
bool isShortable = vault.shortableTokens(_token);
IVault(_vault).setTokenConfig(
_token,
tokenDecimals,
_tokenWeight,
_minProfitBps,
_maxUsdgAmount,
isStable,
isShortable
);
IVault(_vault).setBufferAmount(_token, _bufferAmount);
IVault(_vault).setUsdgAmount(_token, _usdgAmount);
}
function setUsdgAmounts(address _vault, address[] memory _tokens, uint256[] memory _usdgAmounts) external onlyKeeperAndAbove {
for (uint256 i = 0; i < _tokens.length; i++) {
IVault(_vault).setUsdgAmount(_tokens[i], _usdgAmounts[i]);
}
}
function updateUsdgSupply(uint256 usdgAmount) external onlyKeeperAndAbove {
address usdg = IGlpManager(glpManager).usdg();
uint256 balance = IERC20(usdg).balanceOf(glpManager);
IUSDG(usdg).addVault(address(this));
if (usdgAmount > balance) {
uint256 mintAmount = usdgAmount.sub(balance);
IUSDG(usdg).mint(glpManager, mintAmount);
} else {
uint256 burnAmount = balance.sub(usdgAmount);
IUSDG(usdg).burn(glpManager, burnAmount);
}
IUSDG(usdg).removeVault(address(this));
}
function setShortsTrackerAveragePriceWeight(uint256 _shortsTrackerAveragePriceWeight) external onlyAdmin {
IGlpManager(glpManager).setShortsTrackerAveragePriceWeight(_shortsTrackerAveragePriceWeight);
}
function setGlpCooldownDuration(uint256 _cooldownDuration) external onlyAdmin {
require(_cooldownDuration < 2 hours, "Timelock: invalid _cooldownDuration");
IGlpManager(glpManager).setCooldownDuration(_cooldownDuration);
}
function setMaxGlobalShortSize(address _vault, address _token, uint256 _amount) external onlyAdmin {
IVault(_vault).setMaxGlobalShortSize(_token, _amount);
}
function removeAdmin(address _token, address _account) external onlyAdmin {
IYieldToken(_token).removeAdmin(_account);
}
function setIsSwapEnabled(address _vault, bool _isSwapEnabled) external onlyKeeperAndAbove {
IVault(_vault).setIsSwapEnabled(_isSwapEnabled);
}
function setTier(address _referralStorage, uint256 _tierId, uint256 _totalRebate, uint256 _discountShare) external onlyKeeperAndAbove {
IReferralStorage(_referralStorage).setTier(_tierId, _totalRebate, _discountShare);
}
function setReferrerTier(address _referralStorage, address _referrer, uint256 _tierId) external onlyKeeperAndAbove {
IReferralStorage(_referralStorage).setReferrerTier(_referrer, _tierId);
}
function govSetCodeOwner(address _referralStorage, bytes32 _code, address _newAccount) external onlyKeeperAndAbove {
IReferralStorage(_referralStorage).govSetCodeOwner(_code, _newAccount);
}
function setVaultUtils(address _vault, IVaultUtils _vaultUtils) external onlyAdmin {
IVault(_vault).setVaultUtils(_vaultUtils);
}
function setMaxGasPrice(address _vault, uint256 _maxGasPrice) external onlyAdmin {
require(_maxGasPrice > 5000000000, "Invalid _maxGasPrice");
IVault(_vault).setMaxGasPrice(_maxGasPrice);
}
function withdrawFees(address _vault, address _token, address _receiver) external onlyAdmin {
IVault(_vault).withdrawFees(_token, _receiver);
}
function batchWithdrawFees(address _vault, address[] memory _tokens) external onlyKeeperAndAbove {
for (uint256 i = 0; i < _tokens.length; i++) {
IVault(_vault).withdrawFees(_tokens[i], admin);
}
}
function setInPrivateLiquidationMode(address _vault, bool _inPrivateLiquidationMode) external onlyAdmin {
IVault(_vault).setInPrivateLiquidationMode(_inPrivateLiquidationMode);
}
function setLiquidator(address _vault, address _liquidator, bool _isActive) external onlyAdmin {
IVault(_vault).setLiquidator(_liquidator, _isActive);
}
function setInPrivateTransferMode(address _token, bool _inPrivateTransferMode) external onlyAdmin {
IBaseToken(_token).setInPrivateTransferMode(_inPrivateTransferMode);
}
function batchSetBonusRewards(address _vester, address[] memory _accounts, uint256[] memory _amounts) external onlyKeeperAndAbove {
require(_accounts.length == _amounts.length, "Timelock: invalid lengths");
IHandlerTarget(_vester).setHandler(address(this), true);
for (uint256 i = 0; i < _accounts.length; i++) {
address account = _accounts[i];
uint256 amount = _amounts[i];
IVester(_vester).setBonusRewards(account, amount);
}
IHandlerTarget(_vester).setHandler(address(this), false);
}
function transferIn(address _sender, address _token, uint256 _amount) external onlyAdmin {
IERC20(_token).transferFrom(_sender, address(this), _amount);
}
function signalApprove(address _token, address _spender, uint256 _amount) external onlyAdmin {
bytes32 action = keccak256(abi.encodePacked("approve", _token, _spender, _amount));
_setPendingAction(action);
emit SignalApprove(_token, _spender, _amount, action);
}
function approve(address _token, address _spender, uint256 _amount) external onlyAdmin {
bytes32 action = keccak256(abi.encodePacked("approve", _token, _spender, _amount));
_validateAction(action);
_clearAction(action);
IERC20(_token).approve(_spender, _amount);
}
function signalWithdrawToken(address _target, address _token, address _receiver, uint256 _amount) external onlyAdmin {
bytes32 action = keccak256(abi.encodePacked("withdrawToken", _target, _token, _receiver, _amount));
_setPendingAction(action);
emit SignalWithdrawToken(_target, _token, _receiver, _amount, action);
}
function withdrawToken(address _target, address _token, address _receiver, uint256 _amount) external onlyAdmin {
bytes32 action = keccak256(abi.encodePacked("withdrawToken", _target, _token, _receiver, _amount));
_validateAction(action);
_clearAction(action);
IBaseToken(_target).withdrawToken(_token, _receiver, _amount);
}
function signalMint(address _token, address _receiver, uint256 _amount) external onlyAdmin {
bytes32 action = keccak256(abi.encodePacked("mint", _token, _receiver, _amount));
_setPendingAction(action);
emit SignalMint(_token, _receiver, _amount, action);
}
function processMint(address _token, address _receiver, uint256 _amount) external onlyAdmin {
bytes32 action = keccak256(abi.encodePacked("mint", _token, _receiver, _amount));
_validateAction(action);
_clearAction(action);
_mint(_token, _receiver, _amount);
}
function signalSetGov(address _target, address _gov) external override onlyAdmin {
bytes32 action = keccak256(abi.encodePacked("setGov", _target, _gov));
_setPendingAction(action);
emit SignalSetGov(_target, _gov, action);
}
function setGov(address _target, address _gov) external onlyAdmin {
bytes32 action = keccak256(abi.encodePacked("setGov", _target, _gov));
_validateAction(action);
_clearAction(action);
ITimelockTarget(_target).setGov(_gov);
}
function signalSetHandler(address _target, address _handler, bool _isActive) external onlyAdmin {
bytes32 action = keccak256(abi.encodePacked("setHandler", _target, _handler, _isActive));
_setPendingAction(action);
emit SignalSetHandler(_target, _handler, _isActive, action);
}
function setHandler(address _target, address _handler, bool _isActive) external onlyAdmin {
bytes32 action = keccak256(abi.encodePacked("setHandler", _target, _handler, _isActive));
_validateAction(action);
_clearAction(action);
IHandlerTarget(_target).setHandler(_handler, _isActive);
}
function signalSetPriceFeed(address _vault, address _priceFeed) external onlyAdmin {
bytes32 action = keccak256(abi.encodePacked("setPriceFeed", _vault, _priceFeed));
_setPendingAction(action);
emit SignalSetPriceFeed(_vault, _priceFeed, action);
}
function setPriceFeed(address _vault, address _priceFeed) external onlyAdmin {
bytes32 action = keccak256(abi.encodePacked("setPriceFeed", _vault, _priceFeed));
_validateAction(action);
_clearAction(action);
IVault(_vault).setPriceFeed(_priceFeed);
}
function signalRedeemUsdg(address _vault, address _token, uint256 _amount) external onlyAdmin {
bytes32 action = keccak256(abi.encodePacked("redeemUsdg", _vault, _token, _amount));
_setPendingAction(action);
emit SignalRedeemUsdg(_vault, _token, _amount);
}
function redeemUsdg(address _vault, address _token, uint256 _amount) external onlyAdmin {
bytes32 action = keccak256(abi.encodePacked("redeemUsdg", _vault, _token, _amount));
_validateAction(action);
_clearAction(action);
address usdg = IVault(_vault).usdg();
IVault(_vault).setManager(address(this), true);
IUSDG(usdg).addVault(address(this));
IUSDG(usdg).mint(address(this), _amount);
IERC20(usdg).transfer(address(_vault), _amount);
IVault(_vault).sellUSDG(_token, mintReceiver);
IVault(_vault).setManager(address(this), false);
IUSDG(usdg).removeVault(address(this));
}
function signalVaultSetTokenConfig(
address _vault,
address _token,
uint256 _tokenDecimals,
uint256 _tokenWeight,
uint256 _minProfitBps,
uint256 _maxUsdgAmount,
bool _isStable,
bool _isShortable
) external onlyAdmin {
bytes32 action = keccak256(abi.encodePacked(
"vaultSetTokenConfig",
_vault,
_token,
_tokenDecimals,
_tokenWeight,
_minProfitBps,
_maxUsdgAmount,
_isStable,
_isShortable
));
_setPendingAction(action);
emit SignalVaultSetTokenConfig(
_vault,
_token,
_tokenDecimals,
_tokenWeight,
_minProfitBps,
_maxUsdgAmount,
_isStable,
_isShortable
);
}
function vaultSetTokenConfig(
address _vault,
address _token,
uint256 _tokenDecimals,
uint256 _tokenWeight,
uint256 _minProfitBps,
uint256 _maxUsdgAmount,
bool _isStable,
bool _isShortable
) external onlyAdmin {
bytes32 action = keccak256(abi.encodePacked(
"vaultSetTokenConfig",
_vault,
_token,
_tokenDecimals,
_tokenWeight,
_minProfitBps,
_maxUsdgAmount,
_isStable,
_isShortable
));
_validateAction(action);
_clearAction(action);
IVault(_vault).setTokenConfig(
_token,
_tokenDecimals,
_tokenWeight,
_minProfitBps,
_maxUsdgAmount,
_isStable,
_isShortable
);
}
function cancelAction(bytes32 _action) external onlyAdmin {
_clearAction(_action);
}
function _mint(address _token, address _receiver, uint256 _amount) private {
IMintable mintable = IMintable(_token);
mintable.setMinter(address(this), true);
mintable.mint(_receiver, _amount);
require(IERC20(_token).totalSupply() <= maxTokenSupply, "Timelock: maxTokenSupply exceeded");
mintable.setMinter(address(this), false);
}
function _setPendingAction(bytes32 _action) private {
require(pendingActions[_action] == 0, "Timelock: action already signalled");
pendingActions[_action] = block.timestamp.add(buffer);
emit SignalPendingAction(_action);
}
function _validateAction(bytes32 _action) private view {
require(pendingActions[_action] != 0, "Timelock: action not signalled");
require(pendingActions[_action] < block.timestamp, "Timelock: action time not yet passed");
}
function _clearAction(bytes32 _action) private {
require(pendingActions[_action] != 0, "Timelock: invalid _action");
delete pendingActions[_action];
emit ClearAction(_action);
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
interface IReferralStorage {
function codeOwners(bytes32 _code) external view returns (address);
function traderReferralCodes(address _account) external view returns (bytes32);
function referrerDiscountShares(address _account) external view returns (uint256);
function referrerTiers(address _account) external view returns (uint256);
function getTraderReferralInfo(address _account) external view returns (bytes32, address);
function setTraderReferralCode(address _account, bytes32 _code) external;
function setTier(uint256 _tierId, uint256 _totalRebate, uint256 _discountShare) external;
function setReferrerTier(address _referrer, uint256 _tierId) external;
function govSetCodeOwner(bytes32 _code, address _newAccount) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
interface IRewardRouterV2 {
function feeGlpTracker() external view returns (address);
function stakedGlpTracker() external view returns (address);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
interface IVester {
function rewardTracker() external view returns (address);
function claimForAccount(address _account, address _receiver) external returns (uint256);
function claimable(address _account) external view returns (uint256);
function cumulativeClaimAmounts(address _account) external view returns (uint256);
function claimedAmounts(address _account) external view returns (uint256);
function pairAmounts(address _account) external view returns (uint256);
function getVestedAmount(address _account) external view returns (uint256);
function transferredAverageStakedAmounts(address _account) external view returns (uint256);
function transferredCumulativeRewards(address _account) external view returns (uint256);
function cumulativeRewardDeductions(address _account) external view returns (uint256);
function bonusRewards(address _account) external view returns (uint256);
function transferStakeValues(address _sender, address _receiver) external;
function setTransferredAverageStakedAmounts(address _account, uint256 _amount) external;
function setTransferredCumulativeRewards(address _account, uint256 _amount) external;
function setCumulativeRewardDeductions(address _account, uint256 _amount) external;
function setBonusRewards(address _account, uint256 _amount) external;
function getMaxVestableAmount(address _account) external view returns (uint256);
function getCombinedAverageStakedAmount(address _account) external view returns (uint256);
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
interface IBaseToken {
function totalStaked() external view returns (uint256);
function stakedBalance(address _account) external view returns (uint256);
function removeAdmin(address _account) external;
function setInPrivateTransferMode(bool _inPrivateTransferMode) external;
function withdrawToken(address _token, address _account, uint256 _amount) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
interface IMintable {
function isMinter(address _account) external returns (bool);
function setMinter(address _minter, bool _isActive) external;
function mint(address _account, uint256 _amount) external;
function burn(address _account, uint256 _amount) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
interface IUSDG {
function addVault(address _vault) external;
function removeVault(address _vault) external;
function mint(address _account, uint256 _amount) external;
function burn(address _account, uint256 _amount) external;
}
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
interface IYieldToken {
function totalStaked() external view returns (uint256);
function stakedBalance(address _account) external view returns (uint256);
function removeAdmin(address _account) external;
}