Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00
Cross-Chain Transactions
Loading...
Loading
Contract Name:
DLPVault
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 200 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {ERC4626Upgradeable, IERC20Upgradeable} from "@openzeppelin-upgradeable/contracts/token/ERC20/extensions/ERC4626Upgradeable.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {Kernel, Keycode, Permissions, toKeycode, Policy} from "../Kernel.sol";
import {RolesConsumer, ROLESv1} from "../modules/ROLES/OlympusRoles.sol";
import {IDLPVault} from "../interfaces/radiate/IDLPVault.sol";
import {ILeverager} from "../interfaces/radiate/ILeverager.sol";
import {IAToken} from "../interfaces/radiant-interfaces/IAToken.sol";
import {IMultiFeeDistribution} from "../interfaces/radiant-interfaces/IMultiFeeDistribution.sol";
import {ILendingPool} from "../interfaces/radiant-interfaces/ILendingPool.sol";
import {ICreditDelegationToken} from "../interfaces/radiant-interfaces/ICreditDelegationToken.sol";
import {IBountyManager} from "../interfaces/radiant-interfaces/IBountyManager.sol";
import {IPool} from "../interfaces/aave/IPool.sol";
import {IFlashLoanSimpleReceiver} from "../interfaces/aave/IFlashLoanSimpleReceiver.sol";
import {IVault, IAsset, IWETH} from "../interfaces/balancer/IVault.sol";
import {ISwapRouter} from "../interfaces/uniswap/ISwapRouter.sol";
contract DLPVault is
ERC4626Upgradeable,
RolesConsumer,
IFlashLoanSimpleReceiver,
IDLPVault
{
using SafeERC20 for IERC20;
using EnumerableSet for EnumerableSet.UintSet;
//============================================================================================//
// CONSTANT //
//============================================================================================//
string private constant _NAME = "Radiate DLP Vault";
string private constant _SYMBOL = "RADT-DLP";
IERC20 public constant DLP =
IERC20(0x32dF62dc3aEd2cD6224193052Ce665DC18165841);
IERC20 public constant RDNT =
IERC20(0x3082CC23568eA640225c2467653dB90e9250AaA0);
IWETH public constant WETH =
IWETH(0x82aF49447D8a07e3bd95BD0d56f35241523fBab1);
IPool public constant AAVE_LENDING_POOL =
IPool(0x794a61358D6845594F94dc1DB02A252b5b4814aD);
ILendingPool public constant LENDING_POOL =
ILendingPool(0xF4B1486DD74D07706052A33d31d7c0AAFD0659E1);
IMultiFeeDistribution public constant MFD =
IMultiFeeDistribution(0x76ba3eC5f5adBf1C58c91e86502232317EeA72dE);
ISwapRouter public constant SWAP_ROUTER =
ISwapRouter(0xE592427A0AEce92De3Edee1F18E0157C05861564);
IVault public constant VAULT =
IVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8);
bytes32 public constant RDNT_WETH_POOL_ID =
0x32df62dc3aed2cd6224193052ce665dc181658410002000000000000000003bd;
uint256 public constant MAX_QUEUE_PROCESS_LIMIT = 30;
uint256 public constant MAX_QUEUE_PER_WALLET = 5;
uint256 public constant MULTIPLIER = 1e6; // 100%
//============================================================================================//
// STORAGE //
//============================================================================================//
/// @notice kernel
Kernel public kernel;
/// @notice treasury wallet
address public treasury;
/// @notice cap amount of DLP
uint256 public vaultCap;
/// @notice MFD lock index
uint256 public defaultLockIndex;
/// @notice DLP from treasury to boost the APY
uint256 public boostedDLP;
/// @notice rewards from MFD
struct RewardInfo {
address token;
bool isAToken;
uint24 poolFee; // UniswapV3 pool fee
uint256 swapThreshold;
uint256 pending;
}
RewardInfo[] public rewards;
/// @notice fee percent
struct FeeInfo {
uint256 depositFee;
uint256 withdrawFee;
uint256 compoundFee;
}
FeeInfo public fee;
/// @notice withdrawal queue
struct WithdrawalQueue {
address caller;
uint256 assets;
address receiver;
uint32 createdAt;
}
WithdrawalQueue[] public withdrawalQueues;
uint256 public withdrawalQueueIndex;
uint256 public queuedDLP;
uint256 public claimableDLP;
mapping(address => EnumerableSet.UintSet) private _userWithdrawals;
//============================================================================================//
// EVENT //
//============================================================================================//
event KernelChanged(address kernel);
event FeeUpdated(
uint256 depositFee,
uint256 withdrawFee,
uint256 compoundFee
);
event DefaultLockIndexUpdated(uint256 defaultLockIndex);
event RewardBaseTokensAdded(address[] rewardBaseTokens);
event RewardBaseTokensRemoved(address[] rewardBaseTokens);
event VaultCapUpdated(uint256 vaultCap);
event CreditDelegationEnabled(
address indexed token,
address indexed leverager
);
event CreditDelegationDisabled(
address indexed token,
address indexed leverager
);
event WithdrawQueued(
uint256 index,
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
event Claimed(uint256 index, address indexed receiver, uint256 assets);
//============================================================================================//
// ERROR //
//============================================================================================//
error CALLER_NOT_KERNEL();
error CALLER_NOT_AAVE();
error FEE_PERCENT_TOO_HIGH(uint256 fee);
error INVALID_PARAM();
error EXCEED_BOOSTED_AMOUNT();
error EXCEED_VAULT_CAP(uint256 vaultCap);
error TOO_LOW_DEPOSIT();
error EXCEED_MAX_WITHDRAW();
error EXCEED_MAX_REDEEM();
error NOT_CLAIMABLE();
error ALREADY_CALIMED();
error LIMITED_WITHDRAW();
error ZERO_ADDRESS();
//============================================================================================//
// INITIALIZE //
//============================================================================================//
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
function initialize(Kernel _kernel) external initializer {
kernel = _kernel;
defaultLockIndex = 0;
if (DLP.allowance(address(this), address(MFD)) == 0) {
DLP.safeIncreaseAllowance(address(MFD), type(uint256).max);
}
MFD.setRelock(false);
__ERC20_init(_NAME, _SYMBOL);
__ERC4626_init(IERC20Upgradeable(address(DLP)));
}
receive() external payable {}
//============================================================================================//
// MODIFIER //
//============================================================================================//
modifier onlyKernel() {
if (msg.sender != address(kernel)) revert CALLER_NOT_KERNEL();
_;
}
modifier onlyAaveLendingPool() {
if (msg.sender != address(AAVE_LENDING_POOL)) revert CALLER_NOT_AAVE();
_;
}
modifier onlyAdmin() {
ROLES.requireRole("admin", msg.sender);
_;
}
modifier onlyLeverager(address initiator) {
ROLES.requireRole("leverager", initiator);
_;
}
//============================================================================================//
// DEFAULT OVERRIDES //
//============================================================================================//
function changeKernel(Kernel _kernel) external onlyKernel {
kernel = _kernel;
emit KernelChanged(address(_kernel));
}
function isActive() external view returns (bool) {
return kernel.isPolicyActive(Policy(address(this)));
}
function configureDependencies()
external
returns (Keycode[] memory dependencies)
{
dependencies = new Keycode[](2);
dependencies[0] = toKeycode("ROLES");
dependencies[1] = toKeycode("TRSRY");
ROLES = ROLESv1(address(kernel.getModuleForKeycode(dependencies[0])));
treasury = address(kernel.getModuleForKeycode(dependencies[1]));
}
function requestPermissions()
external
pure
returns (Permissions[] memory requests)
{
requests = new Permissions[](0);
}
//============================================================================================//
// ADMIN //
//============================================================================================//
function setFee(
uint256 _depositFee,
uint256 _withdrawFee,
uint256 _compoundFee
) external onlyAdmin {
if (_depositFee >= MULTIPLIER / 2)
revert FEE_PERCENT_TOO_HIGH(_depositFee);
if (_withdrawFee >= MULTIPLIER / 2)
revert FEE_PERCENT_TOO_HIGH(_withdrawFee);
if (_compoundFee >= MULTIPLIER / 2)
revert FEE_PERCENT_TOO_HIGH(_compoundFee);
fee.depositFee = _depositFee;
fee.withdrawFee = _withdrawFee;
fee.compoundFee = _compoundFee;
emit FeeUpdated(_depositFee, _withdrawFee, _compoundFee);
}
function setDefaultLockIndex(uint256 _defaultLockIndex) external onlyAdmin {
defaultLockIndex = _defaultLockIndex;
MFD.setDefaultRelockTypeIndex(_defaultLockIndex);
emit DefaultLockIndexUpdated(_defaultLockIndex);
}
function addRewardBaseTokens(
address[] calldata _rewardBaseTokens,
bool[] calldata _isATokens,
uint24[] calldata _poolFees,
uint256[] calldata _swapThresholds
) external onlyAdmin {
uint256 length = _rewardBaseTokens.length;
if (length != _isATokens.length) revert INVALID_PARAM();
if (length != _poolFees.length) revert INVALID_PARAM();
if (length != _swapThresholds.length) revert INVALID_PARAM();
for (uint256 i = 0; i < length; ) {
rewards.push(
RewardInfo({
token: _rewardBaseTokens[i],
isAToken: _isATokens[i],
poolFee: _poolFees[i],
swapThreshold: _swapThresholds[i],
pending: 0
})
);
unchecked {
++i;
}
}
emit RewardBaseTokensAdded(_rewardBaseTokens);
}
function removeRewardBaseTokens(
address[] calldata _rewardBaseTokens
) external onlyAdmin {
uint256 length = _rewardBaseTokens.length;
for (uint256 i = 0; i < length; ) {
uint256 count = rewards.length;
for (uint256 j = 0; j < count; ) {
if (rewards[j].token == _rewardBaseTokens[i]) {
rewards[j] = rewards[count - 1];
delete rewards[count - 1];
rewards.pop();
break;
}
unchecked {
++j;
}
}
unchecked {
++i;
}
}
emit RewardBaseTokensRemoved(_rewardBaseTokens);
}
function setVaultCap(uint256 _vaultCap) external onlyAdmin {
vaultCap = _vaultCap;
emit VaultCapUpdated(_vaultCap);
}
function enableCreditDelegation(
ICreditDelegationToken _token,
address _leverager
) external onlyAdmin onlyLeverager(_leverager) {
_token.approveDelegation(_leverager, type(uint256).max);
emit CreditDelegationEnabled(address(_token), _leverager);
}
function disableCreditDelegation(
ICreditDelegationToken _token,
address _leverager
) external onlyAdmin {
_token.approveDelegation(_leverager, 0);
emit CreditDelegationDisabled(address(_token), _leverager);
}
function withdrawTokens(address _token) external onlyAdmin {
if (_token == address(0)) {
(bool success, ) = msg.sender.call{value: address(this).balance}(
""
);
require(success);
return;
}
IERC20 token = IERC20(_token);
uint256 amount = token.balanceOf(address(this));
if (token == DLP) {
processWithdrawalQueue();
amount -= claimableDLP;
}
if (amount > 0) {
token.safeTransfer(msg.sender, amount);
}
}
function boostDLP(uint256 _amount) external onlyAdmin {
boostedDLP += _amount;
DLP.safeTransferFrom(msg.sender, address(this), _amount);
_stakeTokens(_amount);
}
function unboostDLP(uint256 _amount) external onlyAdmin {
if (_amount > boostedDLP) revert EXCEED_BOOSTED_AMOUNT();
boostedDLP -= _amount;
queuedDLP += _amount;
uint256 index = withdrawalQueues.length;
withdrawalQueues.push(
WithdrawalQueue({
caller: msg.sender,
assets: _amount,
receiver: msg.sender,
createdAt: uint32(block.timestamp)
})
);
_userWithdrawals[msg.sender].add(index);
}
function getRewardBaseTokens() public view returns (address[] memory) {
uint256 length = rewards.length;
address[] memory rewardBaseTokens = new address[](length);
for (uint256 i = 0; i < length; ) {
rewardBaseTokens[i] = rewards[i].token;
unchecked {
++i;
}
}
return rewardBaseTokens;
}
//============================================================================================//
// FEE LOGIC //
//============================================================================================//
function _sendCompoundFee(
RewardInfo storage _reward,
uint256 _harvested
) internal {
uint256 feeAmount = (_harvested * fee.compoundFee) / MULTIPLIER;
if (feeAmount > 0) {
// feeAmount < harvested < reward.pending
unchecked {
_reward.pending -= feeAmount;
}
IERC20(_reward.token).safeTransfer(treasury, feeAmount);
}
}
function _sendDepositFee(uint256 _assets) internal returns (uint256) {
if (fee.depositFee == 0) return _assets;
uint256 feeAssets = (_assets * fee.depositFee) / MULTIPLIER;
DLP.safeTransferFrom(msg.sender, treasury, feeAssets);
return _assets - feeAssets;
}
function _sendMintFee(uint256 _shares) internal returns (uint256) {
if (fee.depositFee == 0) return _shares;
uint256 feeAssets = (super.previewMint(_shares) * fee.depositFee) /
MULTIPLIER;
uint256 feeShares = super.previewWithdraw(feeAssets);
DLP.safeTransferFrom(msg.sender, treasury, feeAssets);
return _shares - feeShares;
}
function _sendWithdrawFee(
uint256 _assets,
address _owner
) internal returns (uint256) {
if (fee.withdrawFee == 0) return _assets;
uint256 feeShares = (super.previewWithdraw(_assets) * fee.withdrawFee) /
MULTIPLIER;
uint256 feeAssets = super.previewMint(feeShares);
if (msg.sender != _owner) {
super._spendAllowance(_owner, msg.sender, feeShares);
}
super._transfer(_owner, treasury, feeShares);
return _assets - feeAssets;
}
function _sendRedeemFee(
uint256 _shares,
address _owner
) internal returns (uint256) {
if (fee.withdrawFee == 0) return _shares;
uint256 feeShares = (_shares * fee.withdrawFee) / MULTIPLIER;
if (msg.sender != _owner) {
super._spendAllowance(_owner, msg.sender, feeShares);
}
super._transfer(_owner, treasury, feeShares);
return _shares - feeShares;
}
function getFee()
external
view
returns (uint256 depositFee, uint256 withdrawFee, uint256 compoundFee)
{
depositFee = fee.depositFee;
withdrawFee = fee.withdrawFee;
compoundFee = fee.compoundFee;
}
//============================================================================================//
// LEVERAGER LOGIC //
//============================================================================================//
function _min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function executeOperation(
address _asset,
uint256 amount,
uint256 premium,
address initiator,
bytes calldata params
)
external
override
onlyAaveLendingPool
onlyLeverager(initiator)
returns (bool)
{
// approve
if (
IERC20(_asset).allowance(address(this), address(LENDING_POOL)) == 0
) {
IERC20(_asset).safeIncreaseAllowance(
address(LENDING_POOL),
type(uint256).max
);
}
if (
IERC20(_asset).allowance(
address(this),
address(AAVE_LENDING_POOL)
) == 0
) {
IERC20(_asset).safeIncreaseAllowance(
address(AAVE_LENDING_POOL),
type(uint256).max
);
}
// repay looping
uint256 interestRateMode = 2; // variable
LENDING_POOL.repay(_asset, amount, interestRateMode, address(this));
// repay flashloan
LENDING_POOL.withdraw(_asset, amount + premium, address(this));
// withdraw
(uint256 withdrawAmount, address account) = abi.decode(
params,
(uint256, address)
);
LENDING_POOL.withdraw(
_asset,
_min(
withdrawAmount - premium,
IERC20(ILeverager(initiator).getAToken()).balanceOf(
address(this)
)
),
account
);
return true;
}
function withdrawForLeverager(
address _account,
uint256 _amount
) external override onlyLeverager(msg.sender) {
MFD.withdraw(_amount);
RDNT.safeTransfer(_account, _amount);
}
//============================================================================================//
// REWARDS LOGIC //
//============================================================================================//
function compound() public {
if (totalSupply() == 0) return;
// reward balance before
uint256 length = rewards.length;
uint256[] memory balanceBefore = new uint256[](length);
for (uint256 i = 0; i < length; ) {
balanceBefore[i] = IERC20(rewards[i].token).balanceOf(
address(this)
);
unchecked {
++i;
}
}
// get reward
MFD.getReward(getRewardBaseTokens());
// reward harvested
for (uint256 i = 0; i < length; ) {
RewardInfo storage reward = rewards[i];
uint256 harvested = IERC20(reward.token).balanceOf(address(this)) -
balanceBefore[i];
if (harvested > 0) {
// always less than reward token's totalSupply
unchecked {
reward.pending += harvested;
}
_sendCompoundFee(reward, harvested);
_swapToWETH(reward);
}
unchecked {
++i;
}
}
// add liquidity
_joinPool();
// process withdrawal queue
processWithdrawalQueue();
// stake
_stakeDLP();
}
function _swapToWETH(RewardInfo storage _reward) internal {
// Threshold
if (_reward.pending < _reward.swapThreshold) return;
address swapToken;
uint256 swapAmount;
// AToken (withdraw underlying token)
if (_reward.isAToken) {
IERC20(_reward.token).safeIncreaseAllowance(
address(LENDING_POOL),
_reward.pending
);
swapToken = IAToken(_reward.token).UNDERLYING_ASSET_ADDRESS();
(bool success, bytes memory data) = address(LENDING_POOL).call(
abi.encodeWithSignature(
"withdraw(address,uint256,address)",
swapToken,
_reward.pending,
address(this)
)
);
if (success) {
swapAmount = abi.decode(data, (uint256));
} else {
return;
}
}
// ERC20
else {
swapToken = _reward.token;
swapAmount = _reward.pending;
}
_reward.pending = 0;
// UniswapV3 Swap (REWARD -> WETH)
if (swapToken == address(WETH)) {
return;
}
IERC20(swapToken).safeIncreaseAllowance(
address(SWAP_ROUTER),
swapAmount
);
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter
.ExactInputSingleParams({
tokenIn: swapToken,
tokenOut: address(WETH),
fee: _reward.poolFee,
recipient: address(this),
deadline: block.timestamp,
amountIn: swapAmount,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
});
SWAP_ROUTER.exactInputSingle(params);
}
function _joinPool() internal {
uint256 _amountWETH = WETH.balanceOf(address(this));
if (_amountWETH < 0.01 ether) return;
// Balancer Join Pool (WETH <> RDNT)
WETH.approve(address(VAULT), _amountWETH);
IAsset[] memory assets = new IAsset[](2);
assets[0] = IAsset(address(RDNT));
assets[1] = IAsset(address(WETH));
uint256[] memory maxAmountsIn = new uint256[](2);
maxAmountsIn[0] = 0;
maxAmountsIn[1] = _amountWETH;
IVault.JoinPoolRequest memory request;
request.assets = assets;
request.maxAmountsIn = maxAmountsIn;
request.userData = abi.encode(1, maxAmountsIn, 0);
VAULT.joinPool(
RDNT_WETH_POOL_ID,
address(this),
address(this),
request
);
}
function _stakeDLP() internal {
uint256 balance = DLP.balanceOf(address(this));
if (balance > queuedDLP) {
_stakeTokens(balance - queuedDLP);
}
}
function _stakeTokens(uint256 _amount) internal {
if (_amount < IBountyManager(MFD.bountyManager()).minDLPBalance())
return;
MFD.stake(_amount, address(this), defaultLockIndex);
}
function processWithdrawalQueue() public {
// withdraw expired lock
MFD.withdrawExpiredLocksForWithOptions(address(this), 0, true);
uint256 balance = DLP.balanceOf(address(this)) - claimableDLP;
uint256 length = withdrawalQueues.length;
for (
uint256 i = 0;
i < MAX_QUEUE_PROCESS_LIMIT && withdrawalQueueIndex < length;
) {
WithdrawalQueue memory queue = withdrawalQueues[
withdrawalQueueIndex
];
if (balance < queue.assets) {
break;
}
unchecked {
balance -= queue.assets;
claimableDLP += queue.assets;
++withdrawalQueueIndex;
++i;
}
}
}
//============================================================================================//
// ERC4626 OVERRIDES //
//============================================================================================//
function deposit(
uint256 _assets,
address _receiver
) public virtual override returns (uint256) {
compound();
_assets = _sendDepositFee(_assets);
if (totalAssets() + _assets > vaultCap)
revert EXCEED_VAULT_CAP(totalAssets() + _assets);
uint256 shares = super.deposit(_assets, _receiver);
if (shares == 0) revert TOO_LOW_DEPOSIT();
_stakeDLP();
return shares;
}
function mint(
uint256 _shares,
address _receiver
) public virtual override returns (uint256) {
compound();
_shares = _sendMintFee(_shares);
if (_shares == 0) revert TOO_LOW_DEPOSIT();
uint256 assets = super.mint(_shares, _receiver);
if (totalAssets() > vaultCap) revert EXCEED_VAULT_CAP(totalAssets());
_stakeDLP();
return assets;
}
function withdraw(
uint256 _assets,
address _receiver,
address _owner
) public virtual override returns (uint256) {
compound();
if (msg.sender != treasury) {
_assets = _sendWithdrawFee(_assets, _owner);
}
if (_assets > maxWithdraw(_owner)) revert EXCEED_MAX_WITHDRAW();
uint256 shares = super.previewWithdraw(_assets);
_withdraw(msg.sender, _receiver, _owner, _assets, shares);
return shares;
}
function redeem(
uint256 _shares,
address _receiver,
address _owner
) public virtual override returns (uint256) {
compound();
if (msg.sender != treasury) {
_shares = _sendRedeemFee(_shares, _owner);
}
if (_shares > maxRedeem(_owner)) revert EXCEED_MAX_REDEEM();
uint256 assets = super.previewRedeem(_shares);
_withdraw(msg.sender, _receiver, _owner, assets, _shares);
return assets;
}
function claim(uint256 _index) external {
if (_index >= withdrawalQueueIndex) revert NOT_CLAIMABLE();
WithdrawalQueue storage queue = withdrawalQueues[_index];
if (!_userWithdrawals[queue.caller].remove(_index))
revert ALREADY_CALIMED();
queuedDLP -= queue.assets;
claimableDLP -= queue.assets;
DLP.safeTransfer(queue.receiver, queue.assets);
emit Claimed(_index, queue.receiver, queue.assets);
}
function _withdraw(
address _caller,
address _receiver,
address _owner,
uint256 _assets,
uint256 _shares
) internal virtual override {
if (_receiver == address(0)) revert ZERO_ADDRESS();
EnumerableSet.UintSet storage withdrawals = _userWithdrawals[_caller];
if (withdrawals.length() >= MAX_QUEUE_PER_WALLET)
revert LIMITED_WITHDRAW();
if (_caller != _owner) {
super._spendAllowance(_owner, _caller, _shares);
}
super._burn(_owner, _shares);
queuedDLP += _assets;
uint256 index = withdrawalQueues.length;
withdrawalQueues.push(
WithdrawalQueue({
caller: _caller,
assets: _assets,
receiver: _receiver,
createdAt: uint32(block.timestamp)
})
);
withdrawals.add(index);
emit WithdrawQueued(
index,
_caller,
_receiver,
_owner,
_assets,
_shares
);
}
function totalAssets() public view virtual override returns (uint256) {
return
(MFD.totalBalance(address(this)) + DLP.balanceOf(address(this))) -
(queuedDLP + boostedDLP);
}
function withdrawalsOf(
address _account
)
external
view
returns (uint256[] memory indexes, WithdrawalQueue[] memory queues)
{
EnumerableSet.UintSet storage withdrawals = _userWithdrawals[_account];
uint256 length = withdrawals.length();
indexes = new uint256[](length);
queues = new WithdrawalQueue[](length);
for (uint256 i = 0; i < length; ) {
uint256 index = withdrawals.at(i);
indexes[i] = index;
queues[i] = withdrawalQueues[index];
unchecked {
++i;
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @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);
/**
* @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 `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, 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 `from` to `to` 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 from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.1) (token/ERC20/extensions/ERC4626.sol)
pragma solidity ^0.8.0;
import "../ERC20Upgradeable.sol";
import "../utils/SafeERC20Upgradeable.sol";
import "../../../interfaces/IERC4626Upgradeable.sol";
import "../../../utils/math/MathUpgradeable.sol";
import "../../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the ERC4626 "Tokenized Vault Standard" as defined in
* https://eips.ethereum.org/EIPS/eip-4626[EIP-4626].
*
* This extension allows the minting and burning of "shares" (represented using the ERC20 inheritance) in exchange for
* underlying "assets" through standardized {deposit}, {mint}, {redeem} and {burn} workflows. This contract extends
* the ERC20 standard. Any additional extensions included along it would affect the "shares" token represented by this
* contract and not the "assets" token which is an independent contract.
*
* CAUTION: When the vault is empty or nearly empty, deposits are at high risk of being stolen through frontrunning with
* a "donation" to the vault that inflates the price of a share. This is variously known as a donation or inflation
* attack and is essentially a problem of slippage. Vault deployers can protect against this attack by making an initial
* deposit of a non-trivial amount of the asset, such that price manipulation becomes infeasible. Withdrawals may
* similarly be affected by slippage. Users can protect against this attack as well unexpected slippage in general by
* verifying the amount received is as expected, using a wrapper that performs these checks such as
* https://github.com/fei-protocol/ERC4626#erc4626router-and-base[ERC4626Router].
*
* _Available since v4.7._
*/
abstract contract ERC4626Upgradeable is Initializable, ERC20Upgradeable, IERC4626Upgradeable {
using MathUpgradeable for uint256;
IERC20Upgradeable private _asset;
uint8 private _decimals;
/**
* @dev Set the underlying asset contract. This must be an ERC20-compatible contract (ERC20 or ERC777).
*/
function __ERC4626_init(IERC20Upgradeable asset_) internal onlyInitializing {
__ERC4626_init_unchained(asset_);
}
function __ERC4626_init_unchained(IERC20Upgradeable asset_) internal onlyInitializing {
(bool success, uint8 assetDecimals) = _tryGetAssetDecimals(asset_);
_decimals = success ? assetDecimals : super.decimals();
_asset = asset_;
}
/**
* @dev Attempts to fetch the asset decimals. A return value of false indicates that the attempt failed in some way.
*/
function _tryGetAssetDecimals(IERC20Upgradeable asset_) private view returns (bool, uint8) {
(bool success, bytes memory encodedDecimals) = address(asset_).staticcall(
abi.encodeWithSelector(IERC20MetadataUpgradeable.decimals.selector)
);
if (success && encodedDecimals.length >= 32) {
uint256 returnedDecimals = abi.decode(encodedDecimals, (uint256));
if (returnedDecimals <= type(uint8).max) {
return (true, uint8(returnedDecimals));
}
}
return (false, 0);
}
/**
* @dev Decimals are read from the underlying asset in the constructor and cached. If this fails (e.g., the asset
* has not been created yet), the cached value is set to a default obtained by `super.decimals()` (which depends on
* inheritance but is most likely 18). Override this function in order to set a guaranteed hardcoded value.
* See {IERC20Metadata-decimals}.
*/
function decimals() public view virtual override(IERC20MetadataUpgradeable, ERC20Upgradeable) returns (uint8) {
return _decimals;
}
/** @dev See {IERC4626-asset}. */
function asset() public view virtual override returns (address) {
return address(_asset);
}
/** @dev See {IERC4626-totalAssets}. */
function totalAssets() public view virtual override returns (uint256) {
return _asset.balanceOf(address(this));
}
/** @dev See {IERC4626-convertToShares}. */
function convertToShares(uint256 assets) public view virtual override returns (uint256 shares) {
return _convertToShares(assets, MathUpgradeable.Rounding.Down);
}
/** @dev See {IERC4626-convertToAssets}. */
function convertToAssets(uint256 shares) public view virtual override returns (uint256 assets) {
return _convertToAssets(shares, MathUpgradeable.Rounding.Down);
}
/** @dev See {IERC4626-maxDeposit}. */
function maxDeposit(address) public view virtual override returns (uint256) {
return _isVaultCollateralized() ? type(uint256).max : 0;
}
/** @dev See {IERC4626-maxMint}. */
function maxMint(address) public view virtual override returns (uint256) {
return type(uint256).max;
}
/** @dev See {IERC4626-maxWithdraw}. */
function maxWithdraw(address owner) public view virtual override returns (uint256) {
return _convertToAssets(balanceOf(owner), MathUpgradeable.Rounding.Down);
}
/** @dev See {IERC4626-maxRedeem}. */
function maxRedeem(address owner) public view virtual override returns (uint256) {
return balanceOf(owner);
}
/** @dev See {IERC4626-previewDeposit}. */
function previewDeposit(uint256 assets) public view virtual override returns (uint256) {
return _convertToShares(assets, MathUpgradeable.Rounding.Down);
}
/** @dev See {IERC4626-previewMint}. */
function previewMint(uint256 shares) public view virtual override returns (uint256) {
return _convertToAssets(shares, MathUpgradeable.Rounding.Up);
}
/** @dev See {IERC4626-previewWithdraw}. */
function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {
return _convertToShares(assets, MathUpgradeable.Rounding.Up);
}
/** @dev See {IERC4626-previewRedeem}. */
function previewRedeem(uint256 shares) public view virtual override returns (uint256) {
return _convertToAssets(shares, MathUpgradeable.Rounding.Down);
}
/** @dev See {IERC4626-deposit}. */
function deposit(uint256 assets, address receiver) public virtual override returns (uint256) {
require(assets <= maxDeposit(receiver), "ERC4626: deposit more than max");
uint256 shares = previewDeposit(assets);
_deposit(_msgSender(), receiver, assets, shares);
return shares;
}
/** @dev See {IERC4626-mint}.
*
* As opposed to {deposit}, minting is allowed even if the vault is in a state where the price of a share is zero.
* In this case, the shares will be minted without requiring any assets to be deposited.
*/
function mint(uint256 shares, address receiver) public virtual override returns (uint256) {
require(shares <= maxMint(receiver), "ERC4626: mint more than max");
uint256 assets = previewMint(shares);
_deposit(_msgSender(), receiver, assets, shares);
return assets;
}
/** @dev See {IERC4626-withdraw}. */
function withdraw(
uint256 assets,
address receiver,
address owner
) public virtual override returns (uint256) {
require(assets <= maxWithdraw(owner), "ERC4626: withdraw more than max");
uint256 shares = previewWithdraw(assets);
_withdraw(_msgSender(), receiver, owner, assets, shares);
return shares;
}
/** @dev See {IERC4626-redeem}. */
function redeem(
uint256 shares,
address receiver,
address owner
) public virtual override returns (uint256) {
require(shares <= maxRedeem(owner), "ERC4626: redeem more than max");
uint256 assets = previewRedeem(shares);
_withdraw(_msgSender(), receiver, owner, assets, shares);
return assets;
}
/**
* @dev Internal conversion function (from assets to shares) with support for rounding direction.
*
* Will revert if assets > 0, totalSupply > 0 and totalAssets = 0. That corresponds to a case where any asset
* would represent an infinite amount of shares.
*/
function _convertToShares(uint256 assets, MathUpgradeable.Rounding rounding) internal view virtual returns (uint256 shares) {
uint256 supply = totalSupply();
return
(assets == 0 || supply == 0)
? _initialConvertToShares(assets, rounding)
: assets.mulDiv(supply, totalAssets(), rounding);
}
/**
* @dev Internal conversion function (from assets to shares) to apply when the vault is empty.
*
* NOTE: Make sure to keep this function consistent with {_initialConvertToAssets} when overriding it.
*/
function _initialConvertToShares(
uint256 assets,
MathUpgradeable.Rounding /*rounding*/
) internal view virtual returns (uint256 shares) {
return assets;
}
/**
* @dev Internal conversion function (from shares to assets) with support for rounding direction.
*/
function _convertToAssets(uint256 shares, MathUpgradeable.Rounding rounding) internal view virtual returns (uint256 assets) {
uint256 supply = totalSupply();
return
(supply == 0) ? _initialConvertToAssets(shares, rounding) : shares.mulDiv(totalAssets(), supply, rounding);
}
/**
* @dev Internal conversion function (from shares to assets) to apply when the vault is empty.
*
* NOTE: Make sure to keep this function consistent with {_initialConvertToShares} when overriding it.
*/
function _initialConvertToAssets(
uint256 shares,
MathUpgradeable.Rounding /*rounding*/
) internal view virtual returns (uint256 assets) {
return shares;
}
/**
* @dev Deposit/mint common workflow.
*/
function _deposit(
address caller,
address receiver,
uint256 assets,
uint256 shares
) internal virtual {
// If _asset is ERC777, `transferFrom` can trigger a reenterancy BEFORE the transfer happens through the
// `tokensToSend` hook. On the other hand, the `tokenReceived` hook, that is triggered after the transfer,
// calls the vault, which is assumed not malicious.
//
// Conclusion: we need to do the transfer before we mint so that any reentrancy would happen before the
// assets are transferred and before the shares are minted, which is a valid state.
// slither-disable-next-line reentrancy-no-eth
SafeERC20Upgradeable.safeTransferFrom(_asset, caller, address(this), assets);
_mint(receiver, shares);
emit Deposit(caller, receiver, assets, shares);
}
/**
* @dev Withdraw/redeem common workflow.
*/
function _withdraw(
address caller,
address receiver,
address owner,
uint256 assets,
uint256 shares
) internal virtual {
if (caller != owner) {
_spendAllowance(owner, caller, shares);
}
// If _asset is ERC777, `transfer` can trigger a reentrancy AFTER the transfer happens through the
// `tokensReceived` hook. On the other hand, the `tokensToSend` hook, that is triggered before the transfer,
// calls the vault, which is assumed not malicious.
//
// Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the
// shares are burned and after the assets are transferred, which is a valid state.
_burn(owner, shares);
SafeERC20Upgradeable.safeTransfer(_asset, receiver, assets);
emit Withdraw(caller, receiver, owner, assets, shares);
}
/**
* @dev Checks if vault is "healthy" in the sense of having assets backing the circulating shares.
*/
function _isVaultCollateralized() private view returns (bool) {
return totalAssets() > 0 || totalSupply() == 0;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.15;
// ███████ █████ █████ █████ ██████ ██████ ███████████ █████ █████ █████████
// ███░░░░░███ ░░███ ░░███ ░░███ ░░██████ ██████ ░░███░░░░░███░░███ ░░███ ███░░░░░███
// ███ ░░███ ░███ ░░███ ███ ░███░█████░███ ░███ ░███ ░███ ░███ ░███ ░░░
// ░███ ░███ ░███ ░░█████ ░███░░███ ░███ ░██████████ ░███ ░███ ░░█████████
// ░███ ░███ ░███ ░░███ ░███ ░░░ ░███ ░███░░░░░░ ░███ ░███ ░░░░░░░░███
// ░░███ ███ ░███ █ ░███ ░███ ░███ ░███ ░███ ░███ ███ ░███
// ░░░███████░ ███████████ █████ █████ █████ █████ ░░████████ ░░█████████
// ░░░░░░░ ░░░░░░░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░░░░ ░░░░░░░░░
//============================================================================================//
// GLOBAL TYPES //
//============================================================================================//
/// @notice Actions to trigger state changes in the kernel. Passed by the executor
enum Actions {
InstallModule,
UpgradeModule,
ActivatePolicy,
DeactivatePolicy,
ChangeExecutor,
MigrateKernel
}
/// @notice Used by executor to select an action and a target contract for a kernel action
struct Instruction {
Actions action;
address target;
}
/// @notice Used to define which module functions a policy needs access to
struct Permissions {
Keycode keycode;
bytes4 funcSelector;
}
type Keycode is bytes5;
//============================================================================================//
// UTIL FUNCTIONS //
//============================================================================================//
error TargetNotAContract(address target_);
error InvalidKeycode(Keycode keycode_);
// solhint-disable-next-line func-visibility
function toKeycode(bytes5 keycode_) pure returns (Keycode) {
return Keycode.wrap(keycode_);
}
// solhint-disable-next-line func-visibility
function fromKeycode(Keycode keycode_) pure returns (bytes5) {
return Keycode.unwrap(keycode_);
}
// solhint-disable-next-line func-visibility
function ensureContract(address target_) view {
if (target_.code.length == 0) revert TargetNotAContract(target_);
}
// solhint-disable-next-line func-visibility
function ensureValidKeycode(Keycode keycode_) pure {
bytes5 unwrapped = Keycode.unwrap(keycode_);
for (uint256 i = 0; i < 5;) {
bytes1 char = unwrapped[i];
if (char < 0x41 || char > 0x5A) revert InvalidKeycode(keycode_); // A-Z only
unchecked {
i++;
}
}
}
//============================================================================================//
// COMPONENTS //
//============================================================================================//
/// @notice Generic adapter interface for kernel access in modules and policies.
abstract contract KernelAdapter {
error KernelAdapter_OnlyKernel(address caller_);
Kernel public kernel;
constructor(Kernel kernel_) {
kernel = kernel_;
}
/// @notice Modifier to restrict functions to be called only by kernel.
modifier onlyKernel() {
if (msg.sender != address(kernel)) {
revert KernelAdapter_OnlyKernel(msg.sender);
}
_;
}
/// @notice Function used by kernel when migrating to a new kernel.
function changeKernel(Kernel newKernel_) external onlyKernel {
kernel = newKernel_;
}
}
/// @notice Base level extension of the kernel. Modules act as independent state components to be
/// interacted with and mutated through policies.
/// @dev Modules are installed and uninstalled via the executor.
abstract contract Module is KernelAdapter {
error Module_PolicyNotPermitted(address policy_);
constructor(Kernel kernel_) KernelAdapter(kernel_) {}
/// @notice Modifier to restrict which policies have access to module functions.
modifier permissioned() {
if (!kernel.modulePermissions(KEYCODE(), Policy(msg.sender), msg.sig)) {
revert Module_PolicyNotPermitted(msg.sender);
}
_;
}
/// @notice 5 byte identifier for a module.
function KEYCODE() public pure virtual returns (Keycode) {}
/// @notice Returns which semantic version of a module is being implemented.
/// @return major - Major version upgrade indicates breaking change to the interface.
/// @return minor - Minor version change retains backward-compatible interface.
function VERSION() external pure virtual returns (uint8 major, uint8 minor) {}
/// @notice Initialization function for the module
/// @dev This function is called when the module is installed or upgraded by the kernel.
/// @dev MUST BE GATED BY onlyKernel. Used to encompass any initialization or upgrade logic.
function INIT() external virtual onlyKernel {}
}
/// @notice Policies are application logic and external interface for the kernel and installed modules.
/// @dev Policies are activated and deactivated in the kernel by the executor.
/// @dev Module dependencies and function permissions must be defined in appropriate functions.
abstract contract Policy is KernelAdapter {
error Policy_ModuleDoesNotExist(Keycode keycode_);
constructor(Kernel kernel_) KernelAdapter(kernel_) {}
/// @notice Easily accessible indicator for if a policy is activated or not.
function isActive() external view returns (bool) {
return kernel.isPolicyActive(this);
}
/// @notice Function to grab module address from a given keycode.
function getModuleAddress(Keycode keycode_) internal view returns (address) {
address moduleForKeycode = address(kernel.getModuleForKeycode(keycode_));
if (moduleForKeycode == address(0)) {
revert Policy_ModuleDoesNotExist(keycode_);
}
return moduleForKeycode;
}
/// @notice Define module dependencies for this policy.
/// @return dependencies - Keycode array of module dependencies.
function configureDependencies() external virtual returns (Keycode[] memory dependencies) {}
/// @notice Function called by kernel to set module function permissions.
/// @return requests - Array of keycodes and function selectors for requested permissions.
function requestPermissions() external view virtual returns (Permissions[] memory requests) {}
}
/// @notice Main contract that acts as a central component registry for the protocol.
/// @dev The kernel manages modules and policies. The kernel is mutated via predefined Actions,
/// @dev which are input from any address assigned as the executor. The executor can be changed as needed.
contract Kernel {
// ========= EVENTS ========= //
event PermissionsUpdated(Keycode indexed keycode_, Policy indexed policy_, bytes4 funcSelector_, bool granted_);
event ActionExecuted(Actions indexed action_, address indexed target_);
// ========= ERRORS ========= //
error Kernel_OnlyExecutor(address caller_);
error Kernel_ModuleAlreadyInstalled(Keycode module_);
error Kernel_InvalidModuleUpgrade(Keycode module_);
error Kernel_PolicyAlreadyActivated(address policy_);
error Kernel_PolicyNotActivated(address policy_);
// ========= PRIVILEGED ADDRESSES ========= //
/// @notice Address that is able to initiate Actions in the kernel. Can be assigned to a multisig or governance contract.
address public executor;
// ========= MODULE MANAGEMENT ========= //
/// @notice Array of all modules currently installed.
Keycode[] public allKeycodes;
/// @notice Mapping of module address to keycode.
mapping(Keycode => Module) public getModuleForKeycode;
/// @notice Mapping of keycode to module address.
mapping(Module => Keycode) public getKeycodeForModule;
/// @notice Mapping of a keycode to all of its policy dependents. Used to efficiently reconfigure policy dependencies.
mapping(Keycode => Policy[]) public moduleDependents;
/// @notice Helper for module dependent arrays. Prevents the need to loop through array.
mapping(Keycode => mapping(Policy => uint256)) public getDependentIndex;
/// @notice Module <> Policy Permissions.
/// @dev Keycode -> Policy -> Function Selector -> bool for permission
mapping(Keycode => mapping(Policy => mapping(bytes4 => bool))) public modulePermissions;
// ========= POLICY MANAGEMENT ========= //
/// @notice List of all active policies
Policy[] public activePolicies;
/// @notice Helper to get active policy quickly. Prevents need to loop through array.
mapping(Policy => uint256) public getPolicyIndex;
//============================================================================================//
// CORE FUNCTIONS //
//============================================================================================//
constructor() {
executor = msg.sender;
}
/// @notice Modifier to check if caller is the executor.
modifier onlyExecutor() {
if (msg.sender != executor) revert Kernel_OnlyExecutor(msg.sender);
_;
}
function isPolicyActive(Policy policy_) public view returns (bool) {
return activePolicies.length > 0 && activePolicies[getPolicyIndex[policy_]] == policy_;
}
/// @notice Main kernel function. Initiates state changes to kernel depending on Action passed in.
function executeAction(Actions action_, address target_) external onlyExecutor {
if (action_ == Actions.InstallModule) {
ensureContract(target_);
ensureValidKeycode(Module(target_).KEYCODE());
_installModule(Module(target_));
} else if (action_ == Actions.UpgradeModule) {
ensureContract(target_);
ensureValidKeycode(Module(target_).KEYCODE());
_upgradeModule(Module(target_));
} else if (action_ == Actions.ActivatePolicy) {
ensureContract(target_);
_activatePolicy(Policy(target_));
} else if (action_ == Actions.DeactivatePolicy) {
ensureContract(target_);
_deactivatePolicy(Policy(target_));
} else if (action_ == Actions.ChangeExecutor) {
executor = target_;
} else if (action_ == Actions.MigrateKernel) {
ensureContract(target_);
_migrateKernel(Kernel(target_));
}
emit ActionExecuted(action_, target_);
}
function _installModule(Module newModule_) internal {
Keycode keycode = newModule_.KEYCODE();
if (address(getModuleForKeycode[keycode]) != address(0)) {
revert Kernel_ModuleAlreadyInstalled(keycode);
}
getModuleForKeycode[keycode] = newModule_;
getKeycodeForModule[newModule_] = keycode;
allKeycodes.push(keycode);
newModule_.INIT();
}
function _upgradeModule(Module newModule_) internal {
Keycode keycode = newModule_.KEYCODE();
Module oldModule = getModuleForKeycode[keycode];
if (address(oldModule) == address(0) || oldModule == newModule_) {
revert Kernel_InvalidModuleUpgrade(keycode);
}
getKeycodeForModule[oldModule] = Keycode.wrap(bytes5(0));
getKeycodeForModule[newModule_] = keycode;
getModuleForKeycode[keycode] = newModule_;
newModule_.INIT();
_reconfigurePolicies(keycode);
}
function _activatePolicy(Policy policy_) internal {
if (isPolicyActive(policy_)) {
revert Kernel_PolicyAlreadyActivated(address(policy_));
}
// Add policy to list of active policies
activePolicies.push(policy_);
getPolicyIndex[policy_] = activePolicies.length - 1;
// Record module dependencies
Keycode[] memory dependencies = policy_.configureDependencies();
uint256 depLength = dependencies.length;
for (uint256 i; i < depLength;) {
Keycode keycode = dependencies[i];
moduleDependents[keycode].push(policy_);
getDependentIndex[keycode][policy_] = moduleDependents[keycode].length - 1;
unchecked {
++i;
}
}
// Grant permissions for policy to access restricted module functions
Permissions[] memory requests = policy_.requestPermissions();
_setPolicyPermissions(policy_, requests, true);
}
function _deactivatePolicy(Policy policy_) internal {
if (!isPolicyActive(policy_)) {
revert Kernel_PolicyNotActivated(address(policy_));
}
// Revoke permissions
Permissions[] memory requests = policy_.requestPermissions();
_setPolicyPermissions(policy_, requests, false);
// Remove policy from all policy data structures
uint256 idx = getPolicyIndex[policy_];
Policy lastPolicy = activePolicies[activePolicies.length - 1];
activePolicies[idx] = lastPolicy;
activePolicies.pop();
getPolicyIndex[lastPolicy] = idx;
delete getPolicyIndex[policy_];
// Remove policy from module dependents
_pruneFromDependents(policy_);
}
/// @notice All functionality will move to the new kernel. WARNING: ACTION WILL BRICK THIS KERNEL.
/// @dev New kernel must add in all of the modules and policies via executeAction.
/// @dev NOTE: Data does not get cleared from this kernel.
function _migrateKernel(Kernel newKernel_) internal {
uint256 keycodeLen = allKeycodes.length;
for (uint256 i; i < keycodeLen;) {
Module module = Module(getModuleForKeycode[allKeycodes[i]]);
module.changeKernel(newKernel_);
unchecked {
++i;
}
}
uint256 policiesLen = activePolicies.length;
for (uint256 j; j < policiesLen;) {
Policy policy = activePolicies[j];
// Deactivate before changing kernel
policy.changeKernel(newKernel_);
unchecked {
++j;
}
}
}
function _reconfigurePolicies(Keycode keycode_) internal {
Policy[] memory dependents = moduleDependents[keycode_];
uint256 depLength = dependents.length;
for (uint256 i; i < depLength;) {
dependents[i].configureDependencies();
unchecked {
++i;
}
}
}
function _setPolicyPermissions(Policy policy_, Permissions[] memory requests_, bool grant_) internal {
uint256 reqLength = requests_.length;
for (uint256 i = 0; i < reqLength;) {
Permissions memory request = requests_[i];
modulePermissions[request.keycode][policy_][request.funcSelector] = grant_;
emit PermissionsUpdated(request.keycode, policy_, request.funcSelector, grant_);
unchecked {
++i;
}
}
}
function _pruneFromDependents(Policy policy_) internal {
Keycode[] memory dependencies = policy_.configureDependencies();
uint256 depcLength = dependencies.length;
for (uint256 i; i < depcLength;) {
Keycode keycode = dependencies[i];
Policy[] storage dependents = moduleDependents[keycode];
uint256 origIndex = getDependentIndex[keycode][policy_];
Policy lastPolicy = dependents[dependents.length - 1];
// Swap with last and pop
dependents[origIndex] = lastPolicy;
dependents.pop();
// Record new index and delete deactivated policy index
getDependentIndex[keycode][lastPolicy] = origIndex;
delete getDependentIndex[keycode][policy_];
unchecked {
++i;
}
}
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.15;
import {ROLESv1} from "src/modules/ROLES/ROLES.v1.sol";
import "src/Kernel.sol";
/// @notice Abstract contract to have the `onlyRole` modifier
/// @dev Inheriting this automatically makes ROLES module a dependency
abstract contract RolesConsumer {
ROLESv1 public ROLES;
modifier onlyRole(bytes32 role_) {
ROLES.requireRole(role_, msg.sender);
_;
}
}
/// @notice Module that holds multisig roles needed by various policies.
contract OlympusRoles is ROLESv1 {
//============================================================================================//
// MODULE SETUP //
//============================================================================================//
constructor(Kernel kernel_) Module(kernel_) {}
/// @inheritdoc Module
function KEYCODE() public pure override returns (Keycode) {
return toKeycode("ROLES");
}
/// @inheritdoc Module
function VERSION() external pure override returns (uint8 major, uint8 minor) {
major = 1;
minor = 0;
}
//============================================================================================//
// CORE FUNCTIONS //
//============================================================================================//
/// @inheritdoc ROLESv1
function saveRole(bytes32 role_, address addr_) external override permissioned {
if (hasRole[addr_][role_]) {
revert ROLES_AddressAlreadyHasRole(addr_, role_);
}
ensureValidRole(role_);
// Grant role to the address
hasRole[addr_][role_] = true;
emit RoleGranted(role_, addr_);
}
/// @inheritdoc ROLESv1
function removeRole(bytes32 role_, address addr_) external override permissioned {
if (!hasRole[addr_][role_]) {
revert ROLES_AddressDoesNotHaveRole(addr_, role_);
}
hasRole[addr_][role_] = false;
emit RoleRevoked(role_, addr_);
}
//============================================================================================//
// VIEW FUNCTIONS //
//============================================================================================//
/// @inheritdoc ROLESv1
function requireRole(bytes32 role_, address caller_) external view override {
if (!hasRole[caller_][role_]) revert ROLES_RequireRole(role_);
}
/// @inheritdoc ROLESv1
function ensureValidRole(bytes32 role_) public pure override {
for (uint256 i = 0; i < 32;) {
bytes1 char = role_[i];
if ((char < 0x61 || char > 0x7A) && char != 0x5f && char != 0x00) {
revert ROLES_InvalidRole(role_); // a-z only
}
unchecked {
i++;
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
interface IDLPVault {
function withdrawForLeverager(address _account, uint256 _amount) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
interface ILeverager {
function getVDebtToken() external view returns (address);
function getAToken() external view returns (address);
}// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.15;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IScaledBalanceToken} from "./IScaledBalanceToken.sol";
import {IInitializableAToken} from "./IInitializableAToken.sol";
import {IAaveIncentivesController} from "./IAaveIncentivesController.sol";
interface IAToken is IERC20, IScaledBalanceToken, IInitializableAToken {
/**
* @dev Emitted after the mint action
* @param from The address performing the mint
* @param value The amount being
* @param index The new liquidity index of the reserve
*
*/
event Mint(address indexed from, uint256 value, uint256 index);
/**
* @dev Mints `amount` aTokens to `user`
* @param user The address receiving the minted tokens
* @param amount The amount of tokens getting minted
* @param index The new liquidity index of the reserve
* @return `true` if the the previous balance of the user was 0
*/
function mint(address user, uint256 amount, uint256 index) external returns (bool);
/**
* @dev Emitted after aTokens are burned
* @param from The owner of the aTokens, getting them burned
* @param target The address that will receive the underlying
* @param value The amount being burned
* @param index The new liquidity index of the reserve
*
*/
event Burn(address indexed from, address indexed target, uint256 value, uint256 index);
/**
* @dev Emitted during the transfer action
* @param from The user whose tokens are being transferred
* @param to The recipient
* @param value The amount being transferred
* @param index The new liquidity index of the reserve
*
*/
event BalanceTransfer(address indexed from, address indexed to, uint256 value, uint256 index);
/**
* @dev Burns aTokens from `user` and sends the equivalent amount of underlying to `receiverOfUnderlying`
* @param user The owner of the aTokens, getting them burned
* @param receiverOfUnderlying The address that will receive the underlying
* @param amount The amount being burned
* @param index The new liquidity index of the reserve
*
*/
function burn(address user, address receiverOfUnderlying, uint256 amount, uint256 index) external;
/**
* @dev Mints aTokens to the reserve treasury
* @param amount The amount of tokens getting minted
* @param index The new liquidity index of the reserve
*/
function mintToTreasury(uint256 amount, uint256 index) external;
/**
* @dev Transfers aTokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken
* @param from The address getting liquidated, current owner of the aTokens
* @param to The recipient
* @param value The amount of tokens getting transferred
*
*/
function transferOnLiquidation(address from, address to, uint256 value) external;
/**
* @dev Transfers the underlying asset to `target`. Used by the LendingPool to transfer
* assets in borrow(), withdraw() and flashLoan()
* @param user The recipient of the underlying
* @param amount The amount getting transferred
* @return The amount transferred
*
*/
function transferUnderlyingTo(address user, uint256 amount) external returns (uint256);
/**
* @dev Invoked to execute actions on the aToken side after a repayment.
* @param user The user executing the repayment
* @param amount The amount getting repaid
*
*/
function handleRepayment(address user, uint256 amount) external;
/**
* @dev Returns the address of the incentives controller contract
*
*/
function getIncentivesController() external view returns (IAaveIncentivesController);
/**
* @dev Returns the address of the underlying asset of this aToken (E.g. WETH for aWETH)
*
*/
function UNDERLYING_ASSET_ADDRESS() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
pragma abicoder v2;
import "./LockedBalance.sol";
import "./IFeeDistribution.sol";
import "./IMintableToken.sol";
interface IMultiFeeDistribution is IFeeDistribution {
function exit(bool claimRewards) external;
function stake(
uint256 amount,
address onBehalfOf,
uint256 typeIndex
) external;
function rdntToken() external view returns (IMintableToken);
function vestDuration() external view returns (uint256);
function getPriceProvider() external view returns (address);
function lockInfo(
address user
) external view returns (LockedBalance[] memory);
function autocompoundEnabled(address user) external view returns (bool);
function defaultLockIndex(address _user) external view returns (uint256);
function autoRelockDisabled(address user) external view returns (bool);
function totalBalance(address user) external view returns (uint256);
function earnedBalances(
address user
)
external
view
returns (
uint256 total,
uint256 unlocked,
EarnedBalance[] memory earningsData
);
function zapVestingToLp(address _address) external returns (uint256);
function withdrawExpiredLocksFor(
address _address
) external returns (uint256);
function withdrawExpiredLocksForWithOptions(
address _address,
uint256 _limit,
bool _ignoreRelock
) external returns (uint256);
function claimableRewards(
address account
) external view returns (IFeeDistribution.RewardData[] memory rewards);
function setDefaultRelockTypeIndex(uint256 _index) external;
function daoTreasury() external view returns (address);
function stakingToken() external view returns (address);
function claimFromConverter(address) external;
function mint(address user, uint256 amount, bool withPenalty) external;
function withdraw(uint256 amount) external;
function getReward(address[] memory _rewardTokens) external;
function getAllRewards() external;
function relock() external;
function setRelock(bool _status) external;
function bountyManager() external view returns (address);
}
interface IMFDPlus is IMultiFeeDistribution {
function getLastClaimTime(address _user) external returns (uint256);
function claimBounty(
address _user,
bool _execute
) external returns (bool issueBaseBounty);
function claimCompound(
address _user,
bool _execute
) external returns (uint256 bountyAmt);
function setAutocompound(bool _newVal) external;
function getAutocompoundEnabled(address _user) external view returns (bool);
}// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.15;
pragma experimental ABIEncoderV2;
import {ILendingPoolAddressesProvider} from "./ILendingPoolAddressesProvider.sol";
import {DataTypes} from "./DataTypes.sol";
interface ILendingPool {
/**
* @dev Emitted on deposit()
* @param reserve The address of the underlying asset of the reserve
* @param user The address initiating the deposit
* @param onBehalfOf The beneficiary of the deposit, receiving the aTokens
* @param amount The amount deposited
* @param referral The referral code used
*
*/
event Deposit(
address indexed reserve, address user, address indexed onBehalfOf, uint256 amount, uint16 indexed referral
);
/**
* @dev Emitted on withdraw()
* @param reserve The address of the underlyng asset being withdrawn
* @param user The address initiating the withdrawal, owner of aTokens
* @param to Address that will receive the underlying
* @param amount The amount to be withdrawn
*
*/
event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount);
/**
* @dev Emitted on borrow() and flashLoan() when debt needs to be opened
* @param reserve The address of the underlying asset being borrowed
* @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just
* initiator of the transaction on flashLoan()
* @param onBehalfOf The address that will be getting the debt
* @param amount The amount borrowed out
* @param borrowRateMode The rate mode: 1 for Stable, 2 for Variable
* @param borrowRate The numeric rate at which the user has borrowed
* @param referral The referral code used
*
*/
event Borrow(
address indexed reserve,
address user,
address indexed onBehalfOf,
uint256 amount,
uint256 borrowRateMode,
uint256 borrowRate,
uint16 indexed referral
);
/**
* @dev Emitted on repay()
* @param reserve The address of the underlying asset of the reserve
* @param user The beneficiary of the repayment, getting his debt reduced
* @param repayer The address of the user initiating the repay(), providing the funds
* @param amount The amount repaid
*
*/
event Repay(address indexed reserve, address indexed user, address indexed repayer, uint256 amount);
/**
* @dev Emitted on swapBorrowRateMode()
* @param reserve The address of the underlying asset of the reserve
* @param user The address of the user swapping his rate mode
* @param rateMode The rate mode that the user wants to swap to
*
*/
event Swap(address indexed reserve, address indexed user, uint256 rateMode);
/**
* @dev Emitted on setUserUseReserveAsCollateral()
* @param reserve The address of the underlying asset of the reserve
* @param user The address of the user enabling the usage as collateral
*
*/
event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user);
/**
* @dev Emitted on setUserUseReserveAsCollateral()
* @param reserve The address of the underlying asset of the reserve
* @param user The address of the user enabling the usage as collateral
*
*/
event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user);
/**
* @dev Emitted on rebalanceStableBorrowRate()
* @param reserve The address of the underlying asset of the reserve
* @param user The address of the user for which the rebalance has been executed
*
*/
event RebalanceStableBorrowRate(address indexed reserve, address indexed user);
/**
* @dev Emitted on flashLoan()
* @param target The address of the flash loan receiver contract
* @param initiator The address initiating the flash loan
* @param asset The address of the asset being flash borrowed
* @param amount The amount flash borrowed
* @param premium The fee flash borrowed
* @param referralCode The referral code used
*
*/
event FlashLoan(
address indexed target,
address indexed initiator,
address indexed asset,
uint256 amount,
uint256 premium,
uint16 referralCode
);
/**
* @dev Emitted when the pause is triggered.
*/
event Paused();
/**
* @dev Emitted when the pause is lifted.
*/
event Unpaused();
/**
* @dev Emitted when a borrower is liquidated. This event is emitted by the LendingPool via
* LendingPoolCollateral manager using a DELEGATECALL
* This allows to have the events in the generated ABI for LendingPool.
* @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
* @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
* @param user The address of the borrower getting liquidated
* @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
* @param liquidatedCollateralAmount The amount of collateral received by the liiquidator
* @param liquidator The address of the liquidator
* @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants
* to receive the underlying collateral asset directly
*
*/
event LiquidationCall(
address indexed collateralAsset,
address indexed debtAsset,
address indexed user,
uint256 debtToCover,
uint256 liquidatedCollateralAmount,
address liquidator,
bool receiveAToken
);
/**
* @dev Emitted when the state of a reserve is updated. NOTE: This event is actually declared
* in the ReserveLogic library and emitted in the updateInterestRates() function. Since the function is internal,
* the event will actually be fired by the LendingPool contract. The event is therefore replicated here so it
* gets added to the LendingPool ABI
* @param reserve The address of the underlying asset of the reserve
* @param liquidityRate The new liquidity rate
* @param stableBorrowRate The new stable borrow rate
* @param variableBorrowRate The new variable borrow rate
* @param liquidityIndex The new liquidity index
* @param variableBorrowIndex The new variable borrow index
*
*/
event ReserveDataUpdated(
address indexed reserve,
uint256 liquidityRate,
uint256 stableBorrowRate,
uint256 variableBorrowRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex
);
/**
* @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
* - E.g. User deposits 100 USDC and gets in return 100 aUSDC
* @param asset The address of the underlying asset to deposit
* @param amount The amount to be deposited
* @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
* wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
* is a different wallet
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
*
*/
function deposit(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;
function depositWithAutoDLP(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;
/**
* @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned
* E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC
* @param asset The address of the underlying asset to withdraw
* @param amount The underlying amount to be withdrawn
* - Send the value type(uint256).max in order to withdraw the whole aToken balance
* @param to Address that will receive the underlying, same as msg.sender if the user
* wants to receive it on his own wallet, or a different address if the beneficiary is a
* different wallet
* @return The final amount withdrawn
*
*/
function withdraw(address asset, uint256 amount, address to) external returns (uint256);
/**
* @dev Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower
* already deposited enough collateral, or he was given enough allowance by a credit delegator on the
* corresponding debt token (StableDebtToken or VariableDebtToken)
* - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet
* and 100 stable/variable debt tokens, depending on the `interestRateMode`
* @param asset The address of the underlying asset to borrow
* @param amount The amount to be borrowed
* @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
* @param onBehalfOf Address of the user who will receive the debt. Should be the address of the borrower itself
* calling the function if he wants to borrow against his own collateral, or the address of the credit delegator
* if he has been given credit delegation allowance
*
*/
function borrow(address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf)
external;
/**
* @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned
* - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address
* @param asset The address of the borrowed underlying asset previously borrowed
* @param amount The amount to repay
* - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`
* @param rateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable
* @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the
* user calling the function if he wants to reduce/remove his own debt, or the address of any other
* other borrower whose debt should be removed
* @return The final amount repaid
*
*/
function repay(address asset, uint256 amount, uint256 rateMode, address onBehalfOf) external returns (uint256);
/**
* @dev Allows a borrower to swap his debt between stable and variable mode, or viceversa
* @param asset The address of the underlying asset borrowed
* @param rateMode The rate mode that the user wants to swap to
*
*/
function swapBorrowRateMode(address asset, uint256 rateMode) external;
/**
* @dev Rebalances the stable interest rate of a user to the current stable rate defined on the reserve.
* - Users can be rebalanced if the following conditions are satisfied:
* 1. Usage ratio is above 95%
* 2. the current deposit APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too much has been
* borrowed at a stable rate and depositors are not earning enough
* @param asset The address of the underlying asset borrowed
* @param user The address of the user to be rebalanced
*
*/
function rebalanceStableBorrowRate(address asset, address user) external;
/**
* @dev Allows depositors to enable/disable a specific deposited asset as collateral
* @param asset The address of the underlying asset deposited
* @param useAsCollateral `true` if the user wants to use the deposit as collateral, `false` otherwise
*
*/
function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external;
/**
* @dev Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1
* - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives
* a proportionally amount of the `collateralAsset` plus a bonus to cover market risk
* @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
* @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
* @param user The address of the borrower getting liquidated
* @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
* @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants
* to receive the underlying collateral asset directly
*
*/
function liquidationCall(
address collateralAsset,
address debtAsset,
address user,
uint256 debtToCover,
bool receiveAToken
) external;
/**
* @dev Allows smartcontracts to access the liquidity of the pool within one transaction,
* as long as the amount taken plus a fee is returned.
* IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept into consideration.
* For further details please visit https://developers.aave.com
* @param receiverAddress The address of the contract receiving the funds, implementing the IFlashLoanReceiver interface
* @param assets The addresses of the assets being flash-borrowed
* @param amounts The amounts amounts being flash-borrowed
* @param modes Types of the debt to open if the flash loan is not returned:
* 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver
* 1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
* 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
* @param onBehalfOf The address that will receive the debt in the case of using on `modes` 1 or 2
* @param params Variadic packed params to pass to the receiver as extra information
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
*
*/
function flashLoan(
address receiverAddress,
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata modes,
address onBehalfOf,
bytes calldata params,
uint16 referralCode
) external;
/**
* @dev Returns the user account data across all the reserves
* @param user The address of the user
* @return totalCollateralETH the total collateral in ETH of the user
* @return totalDebtETH the total debt in ETH of the user
* @return availableBorrowsETH the borrowing power left of the user
* @return currentLiquidationThreshold the liquidation threshold of the user
* @return ltv the loan to value of the user
* @return healthFactor the current health factor of the user
*
*/
function getUserAccountData(address user)
external
view
returns (
uint256 totalCollateralETH,
uint256 totalDebtETH,
uint256 availableBorrowsETH,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
);
function initReserve(
address reserve,
address aTokenAddress,
address stableDebtAddress,
address variableDebtAddress,
address interestRateStrategyAddress
) external;
function setReserveInterestRateStrategyAddress(address reserve, address rateStrategyAddress) external;
function setConfiguration(address reserve, uint256 configuration) external;
/**
* @dev Returns the configuration of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The configuration of the reserve
*
*/
function getConfiguration(address asset) external view returns (DataTypes.ReserveConfigurationMap memory);
/**
* @dev Returns the configuration of the user across all the reserves
* @param user The user address
* @return The configuration of the user
*
*/
function getUserConfiguration(address user) external view returns (DataTypes.UserConfigurationMap memory);
/**
* @dev Returns the normalized income normalized income of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The reserve's normalized income
*/
function getReserveNormalizedIncome(address asset) external view returns (uint256);
/**
* @dev Returns the normalized variable debt per unit of asset
* @param asset The address of the underlying asset of the reserve
* @return The reserve normalized variable debt
*/
function getReserveNormalizedVariableDebt(address asset) external view returns (uint256);
/**
* @dev Returns the state and configuration of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The state of the reserve
*
*/
function getReserveData(address asset) external view returns (DataTypes.ReserveData memory);
function finalizeTransfer(
address asset,
address from,
address to,
uint256 amount,
uint256 balanceFromAfter,
uint256 balanceToBefore
) external;
function getReservesList() external view returns (address[] memory);
function getAddressesProvider() external view returns (ILendingPoolAddressesProvider);
function setPause(bool val) external;
function paused() external view returns (bool);
}// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.15;
interface ICreditDelegationToken {
event BorrowAllowanceDelegated(address indexed fromUser, address indexed toUser, address asset, uint256 amount);
/**
* @dev delegates borrowing power to a user on the specific debt token
* @param delegatee the address receiving the delegated borrowing power
* @param amount the maximum amount being delegated. Delegation will still
* respect the liquidation constraints (even if delegated, a delegatee cannot
* force a delegator HF to go below 1)
*
*/
function approveDelegation(address delegatee, uint256 amount) external;
/**
* @dev returns the borrow allowance of the user
* @param fromUser The user to giving allowance
* @param toUser The user to give allowance to
* @return the current allowance of toUser
*
*/
function borrowAllowance(address fromUser, address toUser) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
interface IBountyManager {
function quote(address _param) external returns (uint256 bounty);
function claim(address _param) external returns (uint256 bounty);
function minDLPBalance() external view returns (uint256 amt);
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.0;
/**
* @title IPool
* @author Aave
* @notice Defines the basic interface for an Aave Pool.
*/
interface IPool {
/**
* @notice Allows smartcontracts to access the liquidity of the pool within one transaction,
* as long as the amount taken plus a fee is returned.
* @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept
* into consideration. For further details please visit https://docs.aave.com/developers/
* @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanSimpleReceiver interface
* @param asset The address of the asset being flash-borrowed
* @param amount The amount of the asset being flash-borrowed
* @param params Variadic packed params to pass to the receiver as extra information
* @param referralCode The code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
*/
function flashLoanSimple(
address receiverAddress,
address asset,
uint256 amount,
bytes calldata params,
uint16 referralCode
) external;
/**
* @notice Returns the total fee on flash loans
* @return The total fee on flashloans
*/
function FLASHLOAN_PREMIUM_TOTAL() external view returns (uint128);
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.15;
/**
* @title IFlashLoanSimpleReceiver
* @author Aave
* @notice Defines the basic interface of a flashloan-receiver contract.
* @dev Implement this interface to develop a flashloan-compatible flashLoanReceiver contract
*/
interface IFlashLoanSimpleReceiver {
/**
* @notice Executes an operation after receiving the flash-borrowed asset
* @dev Ensure that the contract can return the debt + premium, e.g., has
* enough funds to repay and has approved the Pool to pull the total amount
* @param asset The address of the flash-borrowed asset
* @param amount The amount of the flash-borrowed asset
* @param premium The fee of the flash-borrowed asset
* @param initiator The address of the flashloan initiator
* @param params The byte-encoded params passed when initiating the flashloan
* @return True if the execution of the operation succeeds, false otherwise
*/
function executeOperation(address asset, uint256 amount, uint256 premium, address initiator, bytes calldata params)
external
returns (bool);
}// Modified to remove pesky deps
// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma experimental ABIEncoderV2;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IAsset.sol";
import "./IAuthorizer.sol";
import "./IFlashLoanRecipient.sol";
import "./IProtocolFeesCollector.sol";
import "./IWETH.sol";
pragma solidity >=0.7.0 <0.9.0;
/**
* @dev Full external interface for the Vault core contract - no external or public methods exist in the contract that
* don't override one of these declarations.
*/
interface IVault {
// Generalities about the Vault:
//
// - Whenever documentation refers to 'tokens', it strictly refers to ERC20-compliant token contracts. Tokens are
// transferred out of the Vault by calling the `IERC20.transfer` function, and transferred in by calling
// `IERC20.transferFrom`. In these cases, the sender must have previously allowed the Vault to use their tokens by
// calling `IERC20.approve`. The only deviation from the ERC20 standard that is supported is functions not returning
// a boolean value: in these scenarios, a non-reverting call is assumed to be successful.
//
// - All non-view functions in the Vault are non-reentrant: calling them while another one is mid-execution (e.g.
// while execution control is transferred to a token contract during a swap) will result in a revert. View
// functions can be called in a re-reentrant way, but doing so might cause them to return inconsistent results.
// Contracts calling view functions in the Vault must make sure the Vault has not already been entered.
//
// - View functions revert if referring to either unregistered Pools, or unregistered tokens for registered Pools.
// Authorizer
//
// Some system actions are permissioned, like setting and collecting protocol fees. This permissioning system exists
// outside of the Vault in the Authorizer contract: the Vault simply calls the Authorizer to check if the caller
// can perform a given action.
/**
* @dev Returns the Vault's Authorizer.
*/
function getAuthorizer() external view returns (IAuthorizer);
/**
* @dev Sets a new Authorizer for the Vault. The caller must be allowed by the current Authorizer to do this.
*
* Emits an `AuthorizerChanged` event.
*/
function setAuthorizer(IAuthorizer newAuthorizer) external;
/**
* @dev Emitted when a new authorizer is set by `setAuthorizer`.
*/
event AuthorizerChanged(IAuthorizer indexed newAuthorizer);
// Relayers
//
// Additionally, it is possible for an account to perform certain actions on behalf of another one, using their
// Vault ERC20 allowance and Internal Balance. These accounts are said to be 'relayers' for these Vault functions,
// and are expected to be smart contracts with sound authentication mechanisms. For an account to be able to wield
// this power, two things must occur:
// - The Authorizer must grant the account the permission to be a relayer for the relevant Vault function. This
// means that Balancer governance must approve each individual contract to act as a relayer for the intended
// functions.
// - Each user must approve the relayer to act on their behalf.
// This double protection means users cannot be tricked into approving malicious relayers (because they will not
// have been allowed by the Authorizer via governance), nor can malicious relayers approved by a compromised
// Authorizer or governance drain user funds, since they would also need to be approved by each individual user.
/**
* @dev Returns true if `user` has approved `relayer` to act as a relayer for them.
*/
function hasApprovedRelayer(address user, address relayer) external view returns (bool);
/**
* @dev Allows `relayer` to act as a relayer for `sender` if `approved` is true, and disallows it otherwise.
*
* Emits a `RelayerApprovalChanged` event.
*/
function setRelayerApproval(address sender, address relayer, bool approved) external;
/**
* @dev Emitted every time a relayer is approved or disapproved by `setRelayerApproval`.
*/
event RelayerApprovalChanged(address indexed relayer, address indexed sender, bool approved);
// Internal Balance
//
// Users can deposit tokens into the Vault, where they are allocated to their Internal Balance, and later
// transferred or withdrawn. It can also be used as a source of tokens when joining Pools, as a destination
// when exiting them, and as either when performing swaps. This usage of Internal Balance results in greatly reduced
// gas costs when compared to relying on plain ERC20 transfers, leading to large savings for frequent users.
//
// Internal Balance management features batching, which means a single contract call can be used to perform multiple
// operations of different kinds, with different senders and recipients, at once.
/**
* @dev Returns `user`'s Internal Balance for a set of tokens.
*/
function getInternalBalance(address user, IERC20[] memory tokens) external view returns (uint256[] memory);
/**
* @dev Performs a set of user balance operations, which involve Internal Balance (deposit, withdraw or transfer)
* and plain ERC20 transfers using the Vault's allowance. This last feature is particularly useful for relayers, as
* it lets integrators reuse a user's Vault allowance.
*
* For each operation, if the caller is not `sender`, it must be an authorized relayer for them.
*/
function manageUserBalance(UserBalanceOp[] memory ops) external payable;
/**
* @dev Data for `manageUserBalance` operations, which include the possibility for ETH to be sent and received
* without manual WETH wrapping or unwrapping.
*/
struct UserBalanceOp {
UserBalanceOpKind kind;
IAsset asset;
uint256 amount;
address sender;
address payable recipient;
}
// There are four possible operations in `manageUserBalance`:
//
// - DEPOSIT_INTERNAL
// Increases the Internal Balance of the `recipient` account by transferring tokens from the corresponding
// `sender`. The sender must have allowed the Vault to use their tokens via `IERC20.approve()`.
//
// ETH can be used by passing the ETH sentinel value as the asset and forwarding ETH in the call: it will be wrapped
// and deposited as WETH. Any ETH amount remaining will be sent back to the caller (not the sender, which is
// relevant for relayers).
//
// Emits an `InternalBalanceChanged` event.
//
//
// - WITHDRAW_INTERNAL
// Decreases the Internal Balance of the `sender` account by transferring tokens to the `recipient`.
//
// ETH can be used by passing the ETH sentinel value as the asset. This will deduct WETH instead, unwrap it and send
// it to the recipient as ETH.
//
// Emits an `InternalBalanceChanged` event.
//
//
// - TRANSFER_INTERNAL
// Transfers tokens from the Internal Balance of the `sender` account to the Internal Balance of `recipient`.
//
// Reverts if the ETH sentinel value is passed.
//
// Emits an `InternalBalanceChanged` event.
//
//
// - TRANSFER_EXTERNAL
// Transfers tokens from `sender` to `recipient`, using the Vault's ERC20 allowance. This is typically used by
// relayers, as it lets them reuse a user's Vault allowance.
//
// Reverts if the ETH sentinel value is passed.
//
// Emits an `ExternalBalanceTransfer` event.
enum UserBalanceOpKind {
DEPOSIT_INTERNAL,
WITHDRAW_INTERNAL,
TRANSFER_INTERNAL,
TRANSFER_EXTERNAL
}
/**
* @dev Emitted when a user's Internal Balance changes, either from calls to `manageUserBalance`, or through
* interacting with Pools using Internal Balance.
*
* Because Internal Balance works exclusively with ERC20 tokens, ETH deposits and withdrawals will use the WETH
* address.
*/
event InternalBalanceChanged(address indexed user, IERC20 indexed token, int256 delta);
/**
* @dev Emitted when a user's Vault ERC20 allowance is used by the Vault to transfer tokens to an external account.
*/
event ExternalBalanceTransfer(IERC20 indexed token, address indexed sender, address recipient, uint256 amount);
// Pools
//
// There are three specialization settings for Pools, which allow for cheaper swaps at the cost of reduced
// functionality:
//
// - General: no specialization, suited for all Pools. IGeneralPool is used for swap request callbacks, passing the
// balance of all tokens in the Pool. These Pools have the largest swap costs (because of the extra storage reads),
// which increase with the number of registered tokens.
//
// - Minimal Swap Info: IMinimalSwapInfoPool is used instead of IGeneralPool, which saves gas by only passing the
// balance of the two tokens involved in the swap. This is suitable for some pricing algorithms, like the weighted
// constant product one popularized by Balancer V1. Swap costs are smaller compared to general Pools, and are
// independent of the number of registered tokens.
//
// - Two Token: only allows two tokens to be registered. This achieves the lowest possible swap gas cost. Like
// minimal swap info Pools, these are called via IMinimalSwapInfoPool.
enum PoolSpecialization {
GENERAL,
MINIMAL_SWAP_INFO,
TWO_TOKEN
}
/**
* @dev Registers the caller account as a Pool with a given specialization setting. Returns the Pool's ID, which
* is used in all Pool-related functions. Pools cannot be deregistered, nor can the Pool's specialization be
* changed.
*
* The caller is expected to be a smart contract that implements either `IGeneralPool` or `IMinimalSwapInfoPool`,
* depending on the chosen specialization setting. This contract is known as the Pool's contract.
*
* Note that the same contract may register itself as multiple Pools with unique Pool IDs, or in other words,
* multiple Pools may share the same contract.
*
* Emits a `PoolRegistered` event.
*/
function registerPool(PoolSpecialization specialization) external returns (bytes32);
/**
* @dev Emitted when a Pool is registered by calling `registerPool`.
*/
event PoolRegistered(bytes32 indexed poolId, address indexed poolAddress, PoolSpecialization specialization);
/**
* @dev Returns a Pool's contract address and specialization setting.
*/
function getPool(bytes32 poolId) external view returns (address, PoolSpecialization);
/**
* @dev Registers `tokens` for the `poolId` Pool. Must be called by the Pool's contract.
*
* Pools can only interact with tokens they have registered. Users join a Pool by transferring registered tokens,
* exit by receiving registered tokens, and can only swap registered tokens.
*
* Each token can only be registered once. For Pools with the Two Token specialization, `tokens` must have a length
* of two, that is, both tokens must be registered in the same `registerTokens` call, and they must be sorted in
* ascending order.
*
* The `tokens` and `assetManagers` arrays must have the same length, and each entry in these indicates the Asset
* Manager for the corresponding token. Asset Managers can manage a Pool's tokens via `managePoolBalance`,
* depositing and withdrawing them directly, and can even set their balance to arbitrary amounts. They are therefore
* expected to be highly secured smart contracts with sound design principles, and the decision to register an
* Asset Manager should not be made lightly.
*
* Pools can choose not to assign an Asset Manager to a given token by passing in the zero address. Once an Asset
* Manager is set, it cannot be changed except by deregistering the associated token and registering again with a
* different Asset Manager.
*
* Emits a `TokensRegistered` event.
*/
function registerTokens(bytes32 poolId, IERC20[] memory tokens, address[] memory assetManagers) external;
/**
* @dev Emitted when a Pool registers tokens by calling `registerTokens`.
*/
event TokensRegistered(bytes32 indexed poolId, IERC20[] tokens, address[] assetManagers);
/**
* @dev Deregisters `tokens` for the `poolId` Pool. Must be called by the Pool's contract.
*
* Only registered tokens (via `registerTokens`) can be deregistered. Additionally, they must have zero total
* balance. For Pools with the Two Token specialization, `tokens` must have a length of two, that is, both tokens
* must be deregistered in the same `deregisterTokens` call.
*
* A deregistered token can be re-registered later on, possibly with a different Asset Manager.
*
* Emits a `TokensDeregistered` event.
*/
function deregisterTokens(bytes32 poolId, IERC20[] memory tokens) external;
/**
* @dev Emitted when a Pool deregisters tokens by calling `deregisterTokens`.
*/
event TokensDeregistered(bytes32 indexed poolId, IERC20[] tokens);
/**
* @dev Returns detailed information for a Pool's registered token.
*
* `cash` is the number of tokens the Vault currently holds for the Pool. `managed` is the number of tokens
* withdrawn and held outside the Vault by the Pool's token Asset Manager. The Pool's total balance for `token`
* equals the sum of `cash` and `managed`.
*
* Internally, `cash` and `managed` are stored using 112 bits. No action can ever cause a Pool's token `cash`,
* `managed` or `total` balance to be greater than 2^112 - 1.
*
* `lastChangeBlock` is the number of the block in which `token`'s total balance was last modified (via either a
* join, exit, swap, or Asset Manager update). This value is useful to avoid so-called 'sandwich attacks', for
* example when developing price oracles. A change of zero (e.g. caused by a swap with amount zero) is considered a
* change for this purpose, and will update `lastChangeBlock`.
*
* `assetManager` is the Pool's token Asset Manager.
*/
function getPoolTokenInfo(bytes32 poolId, IERC20 token)
external
view
returns (uint256 cash, uint256 managed, uint256 lastChangeBlock, address assetManager);
/**
* @dev Returns a Pool's registered tokens, the total balance for each, and the latest block when *any* of
* the tokens' `balances` changed.
*
* The order of the `tokens` array is the same order that will be used in `joinPool`, `exitPool`, as well as in all
* Pool hooks (where applicable). Calls to `registerTokens` and `deregisterTokens` may change this order.
*
* If a Pool only registers tokens once, and these are sorted in ascending order, they will be stored in the same
* order as passed to `registerTokens`.
*
* Total balances include both tokens held by the Vault and those withdrawn by the Pool's Asset Managers. These are
* the amounts used by joins, exits and swaps. For a detailed breakdown of token balances, use `getPoolTokenInfo`
* instead.
*/
function getPoolTokens(bytes32 poolId)
external
view
returns (IERC20[] memory tokens, uint256[] memory balances, uint256 lastChangeBlock);
/**
* @dev Called by users to join a Pool, which transfers tokens from `sender` into the Pool's balance. This will
* trigger custom Pool behavior, which will typically grant something in return to `recipient` - often tokenized
* Pool shares.
*
* If the caller is not `sender`, it must be an authorized relayer for them.
*
* The `assets` and `maxAmountsIn` arrays must have the same length, and each entry indicates the maximum amount
* to send for each asset. The amounts to send are decided by the Pool and not the Vault: it just enforces
* these maximums.
*
* If joining a Pool that holds WETH, it is possible to send ETH directly: the Vault will do the wrapping. To enable
* this mechanism, the IAsset sentinel value (the zero address) must be passed in the `assets` array instead of the
* WETH address. Note that it is not possible to combine ETH and WETH in the same join. Any excess ETH will be sent
* back to the caller (not the sender, which is important for relayers).
*
* `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when
* interacting with Pools that register and deregister tokens frequently. If sending ETH however, the array must be
* sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the final
* `assets` array might not be sorted. Pools with no registered tokens cannot be joined.
*
* If `fromInternalBalance` is true, the caller's Internal Balance will be preferred: ERC20 transfers will only
* be made for the difference between the requested amount and Internal Balance (if any). Note that ETH cannot be
* withdrawn from Internal Balance: attempting to do so will trigger a revert.
*
* This causes the Vault to call the `IBasePool.onJoinPool` hook on the Pool's contract, where Pools implement
* their own custom logic. This typically requires additional information from the user (such as the expected number
* of Pool shares). This can be encoded in the `userData` argument, which is ignored by the Vault and passed
* directly to the Pool's contract, as is `recipient`.
*
* Emits a `PoolBalanceChanged` event.
*/
function joinPool(bytes32 poolId, address sender, address recipient, JoinPoolRequest memory request)
external
payable;
struct JoinPoolRequest {
IAsset[] assets;
uint256[] maxAmountsIn;
bytes userData;
bool fromInternalBalance;
}
/**
* @dev Called by users to exit a Pool, which transfers tokens from the Pool's balance to `recipient`. This will
* trigger custom Pool behavior, which will typically ask for something in return from `sender` - often tokenized
* Pool shares. The amount of tokens that can be withdrawn is limited by the Pool's `cash` balance (see
* `getPoolTokenInfo`).
*
* If the caller is not `sender`, it must be an authorized relayer for them.
*
* The `tokens` and `minAmountsOut` arrays must have the same length, and each entry in these indicates the minimum
* token amount to receive for each token contract. The amounts to send are decided by the Pool and not the Vault:
* it just enforces these minimums.
*
* If exiting a Pool that holds WETH, it is possible to receive ETH directly: the Vault will do the unwrapping. To
* enable this mechanism, the IAsset sentinel value (the zero address) must be passed in the `assets` array instead
* of the WETH address. Note that it is not possible to combine ETH and WETH in the same exit.
*
* `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when
* interacting with Pools that register and deregister tokens frequently. If receiving ETH however, the array must
* be sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the
* final `assets` array might not be sorted. Pools with no registered tokens cannot be exited.
*
* If `toInternalBalance` is true, the tokens will be deposited to `recipient`'s Internal Balance. Otherwise,
* an ERC20 transfer will be performed. Note that ETH cannot be deposited to Internal Balance: attempting to
* do so will trigger a revert.
*
* `minAmountsOut` is the minimum amount of tokens the user expects to get out of the Pool, for each token in the
* `tokens` array. This array must match the Pool's registered tokens.
*
* This causes the Vault to call the `IBasePool.onExitPool` hook on the Pool's contract, where Pools implement
* their own custom logic. This typically requires additional information from the user (such as the expected number
* of Pool shares to return). This can be encoded in the `userData` argument, which is ignored by the Vault and
* passed directly to the Pool's contract.
*
* Emits a `PoolBalanceChanged` event.
*/
function exitPool(bytes32 poolId, address sender, address payable recipient, ExitPoolRequest memory request)
external;
struct ExitPoolRequest {
IAsset[] assets;
uint256[] minAmountsOut;
bytes userData;
bool toInternalBalance;
}
/**
* @dev Emitted when a user joins or exits a Pool by calling `joinPool` or `exitPool`, respectively.
*/
event PoolBalanceChanged(
bytes32 indexed poolId,
address indexed liquidityProvider,
IERC20[] tokens,
int256[] deltas,
uint256[] protocolFeeAmounts
);
enum PoolBalanceChangeKind {
JOIN,
EXIT
}
// Swaps
//
// Users can swap tokens with Pools by calling the `swap` and `batchSwap` functions. To do this,
// they need not trust Pool contracts in any way: all security checks are made by the Vault. They must however be
// aware of the Pools' pricing algorithms in order to estimate the prices Pools will quote.
//
// The `swap` function executes a single swap, while `batchSwap` can perform multiple swaps in sequence.
// In each individual swap, tokens of one kind are sent from the sender to the Pool (this is the 'token in'),
// and tokens of another kind are sent from the Pool to the recipient in exchange (this is the 'token out').
// More complex swaps, such as one token in to multiple tokens out can be achieved by batching together
// individual swaps.
//
// There are two swap kinds:
// - 'given in' swaps, where the amount of tokens in (sent to the Pool) is known, and the Pool determines (via the
// `onSwap` hook) the amount of tokens out (to send to the recipient).
// - 'given out' swaps, where the amount of tokens out (received from the Pool) is known, and the Pool determines
// (via the `onSwap` hook) the amount of tokens in (to receive from the sender).
//
// Additionally, it is possible to chain swaps using a placeholder input amount, which the Vault replaces with
// the calculated output of the previous swap. If the previous swap was 'given in', this will be the calculated
// tokenOut amount. If the previous swap was 'given out', it will use the calculated tokenIn amount. These extended
// swaps are known as 'multihop' swaps, since they 'hop' through a number of intermediate tokens before arriving at
// the final intended token.
//
// In all cases, tokens are only transferred in and out of the Vault (or withdrawn from and deposited into Internal
// Balance) after all individual swaps have been completed, and the net token balance change computed. This makes
// certain swap patterns, such as multihops, or swaps that interact with the same token pair in multiple Pools, cost
// much less gas than they would otherwise.
//
// It also means that under certain conditions it is possible to perform arbitrage by swapping with multiple
// Pools in a way that results in net token movement out of the Vault (profit), with no tokens being sent in (only
// updating the Pool's internal accounting).
//
// To protect users from front-running or the market changing rapidly, they supply a list of 'limits' for each token
// involved in the swap, where either the maximum number of tokens to send (by passing a positive value) or the
// minimum amount of tokens to receive (by passing a negative value) is specified.
//
// Additionally, a 'deadline' timestamp can also be provided, forcing the swap to fail if it occurs after
// this point in time (e.g. if the transaction failed to be included in a block promptly).
//
// If interacting with Pools that hold WETH, it is possible to both send and receive ETH directly: the Vault will do
// the wrapping and unwrapping. To enable this mechanism, the IAsset sentinel value (the zero address) must be
// passed in the `assets` array instead of the WETH address. Note that it is possible to combine ETH and WETH in the
// same swap. Any excess ETH will be sent back to the caller (not the sender, which is relevant for relayers).
//
// Finally, Internal Balance can be used when either sending or receiving tokens.
enum SwapKind {
GIVEN_IN,
GIVEN_OUT
}
/**
* @dev Performs a swap with a single Pool.
*
* If the swap is 'given in' (the number of tokens to send to the Pool is known), it returns the amount of tokens
* taken from the Pool, which must be greater than or equal to `limit`.
*
* If the swap is 'given out' (the number of tokens to take from the Pool is known), it returns the amount of tokens
* sent to the Pool, which must be less than or equal to `limit`.
*
* Internal Balance usage and the recipient are determined by the `funds` struct.
*
* Emits a `Swap` event.
*/
function swap(SingleSwap memory singleSwap, FundManagement memory funds, uint256 limit, uint256 deadline)
external
payable
returns (uint256);
/**
* @dev Data for a single swap executed by `swap`. `amount` is either `amountIn` or `amountOut` depending on
* the `kind` value.
*
* `assetIn` and `assetOut` are either token addresses, or the IAsset sentinel value for ETH (the zero address).
* Note that Pools never interact with ETH directly: it will be wrapped to or unwrapped from WETH by the Vault.
*
* The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be
* used to extend swap behavior.
*/
struct SingleSwap {
bytes32 poolId;
SwapKind kind;
IAsset assetIn;
IAsset assetOut;
uint256 amount;
bytes userData;
}
/**
* @dev Performs a series of swaps with one or multiple Pools. In each individual swap, the caller determines either
* the amount of tokens sent to or received from the Pool, depending on the `kind` value.
*
* Returns an array with the net Vault asset balance deltas. Positive amounts represent tokens (or ETH) sent to the
* Vault, and negative amounts represent tokens (or ETH) sent by the Vault. Each delta corresponds to the asset at
* the same index in the `assets` array.
*
* Swaps are executed sequentially, in the order specified by the `swaps` array. Each array element describes a
* Pool, the token to be sent to this Pool, the token to receive from it, and an amount that is either `amountIn` or
* `amountOut` depending on the swap kind.
*
* Multihop swaps can be executed by passing an `amount` value of zero for a swap. This will cause the amount in/out
* of the previous swap to be used as the amount in for the current one. In a 'given in' swap, 'tokenIn' must equal
* the previous swap's `tokenOut`. For a 'given out' swap, `tokenOut` must equal the previous swap's `tokenIn`.
*
* The `assets` array contains the addresses of all assets involved in the swaps. These are either token addresses,
* or the IAsset sentinel value for ETH (the zero address). Each entry in the `swaps` array specifies tokens in and
* out by referencing an index in `assets`. Note that Pools never interact with ETH directly: it will be wrapped to
* or unwrapped from WETH by the Vault.
*
* Internal Balance usage, sender, and recipient are determined by the `funds` struct. The `limits` array specifies
* the minimum or maximum amount of each token the vault is allowed to transfer.
*
* `batchSwap` can be used to make a single swap, like `swap` does, but doing so requires more gas than the
* equivalent `swap` call.
*
* Emits `Swap` events.
*/
function batchSwap(
SwapKind kind,
BatchSwapStep[] memory swaps,
IAsset[] memory assets,
FundManagement memory funds,
int256[] memory limits,
uint256 deadline
) external payable returns (int256[] memory);
/**
* @dev Data for each individual swap executed by `batchSwap`. The asset in and out fields are indexes into the
* `assets` array passed to that function, and ETH assets are converted to WETH.
*
* If `amount` is zero, the multihop mechanism is used to determine the actual amount based on the amount in/out
* from the previous swap, depending on the swap kind.
*
* The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be
* used to extend swap behavior.
*/
struct BatchSwapStep {
bytes32 poolId;
uint256 assetInIndex;
uint256 assetOutIndex;
uint256 amount;
bytes userData;
}
/**
* @dev Emitted for each individual swap performed by `swap` or `batchSwap`.
*/
event Swap(
bytes32 indexed poolId, IERC20 indexed tokenIn, IERC20 indexed tokenOut, uint256 amountIn, uint256 amountOut
);
/**
* @dev All tokens in a swap are either sent from the `sender` account to the Vault, or from the Vault to the
* `recipient` account.
*
* If the caller is not `sender`, it must be an authorized relayer for them.
*
* If `fromInternalBalance` is true, the `sender`'s Internal Balance will be preferred, performing an ERC20
* transfer for the difference between the requested amount and the User's Internal Balance (if any). The `sender`
* must have allowed the Vault to use their tokens via `IERC20.approve()`. This matches the behavior of
* `joinPool`.
*
* If `toInternalBalance` is true, tokens will be deposited to `recipient`'s internal balance instead of
* transferred. This matches the behavior of `exitPool`.
*
* Note that ETH cannot be deposited to or withdrawn from Internal Balance: attempting to do so will trigger a
* revert.
*/
struct FundManagement {
address sender;
bool fromInternalBalance;
address payable recipient;
bool toInternalBalance;
}
/**
* @dev Simulates a call to `batchSwap`, returning an array of Vault asset deltas. Calls to `swap` cannot be
* simulated directly, but an equivalent `batchSwap` call can and will yield the exact same result.
*
* Each element in the array corresponds to the asset at the same index, and indicates the number of tokens (or ETH)
* the Vault would take from the sender (if positive) or send to the recipient (if negative). The arguments it
* receives are the same that an equivalent `batchSwap` call would receive.
*
* Unlike `batchSwap`, this function performs no checks on the sender or recipient field in the `funds` struct.
* This makes it suitable to be called by off-chain applications via eth_call without needing to hold tokens,
* approve them for the Vault, or even know a user's address.
*
* Note that this function is not 'view' (due to implementation details): the client code must explicitly execute
* eth_call instead of eth_sendTransaction.
*/
function queryBatchSwap(
SwapKind kind,
BatchSwapStep[] memory swaps,
IAsset[] memory assets,
FundManagement memory funds
) external returns (int256[] memory assetDeltas);
// Flash Loans
/**
* @dev Performs a 'flash loan', sending tokens to `recipient`, executing the `receiveFlashLoan` hook on it,
* and then reverting unless the tokens plus a proportional protocol fee have been returned.
*
* The `tokens` and `amounts` arrays must have the same length, and each entry in these indicates the loan amount
* for each token contract. `tokens` must be sorted in ascending order.
*
* The 'userData' field is ignored by the Vault, and forwarded as-is to `recipient` as part of the
* `receiveFlashLoan` call.
*
* Emits `FlashLoan` events.
*/
function flashLoan(
IFlashLoanRecipient recipient,
IERC20[] memory tokens,
uint256[] memory amounts,
bytes memory userData
) external;
/**
* @dev Emitted for each individual flash loan performed by `flashLoan`.
*/
event FlashLoan(IFlashLoanRecipient indexed recipient, IERC20 indexed token, uint256 amount, uint256 feeAmount);
// Asset Management
//
// Each token registered for a Pool can be assigned an Asset Manager, which is able to freely withdraw the Pool's
// tokens from the Vault, deposit them, or assign arbitrary values to its `managed` balance (see
// `getPoolTokenInfo`). This makes them extremely powerful and dangerous. Even if an Asset Manager only directly
// controls one of the tokens in a Pool, a malicious manager could set that token's balance to manipulate the
// prices of the other tokens, and then drain the Pool with swaps. The risk of using Asset Managers is therefore
// not constrained to the tokens they are managing, but extends to the entire Pool's holdings.
//
// However, a properly designed Asset Manager smart contract can be safely used for the Pool's benefit,
// for example by lending unused tokens out for interest, or using them to participate in voting protocols.
//
// This concept is unrelated to the IAsset interface.
/**
* @dev Performs a set of Pool balance operations, which may be either withdrawals, deposits or updates.
*
* Pool Balance management features batching, which means a single contract call can be used to perform multiple
* operations of different kinds, with different Pools and tokens, at once.
*
* For each operation, the caller must be registered as the Asset Manager for `token` in `poolId`.
*/
function managePoolBalance(PoolBalanceOp[] memory ops) external;
struct PoolBalanceOp {
PoolBalanceOpKind kind;
bytes32 poolId;
IERC20 token;
uint256 amount;
}
/**
* Withdrawals decrease the Pool's cash, but increase its managed balance, leaving the total balance unchanged.
*
* Deposits increase the Pool's cash, but decrease its managed balance, leaving the total balance unchanged.
*
* Updates don't affect the Pool's cash balance, but because the managed balance changes, it does alter the total.
* The external amount can be either increased or decreased by this call (i.e., reporting a gain or a loss).
*/
enum PoolBalanceOpKind {
WITHDRAW,
DEPOSIT,
UPDATE
}
/**
* @dev Emitted when a Pool's token Asset Manager alters its balance via `managePoolBalance`.
*/
event PoolBalanceManaged(
bytes32 indexed poolId,
address indexed assetManager,
IERC20 indexed token,
int256 cashDelta,
int256 managedDelta
);
// Protocol Fees
//
// Some operations cause the Vault to collect tokens in the form of protocol fees, which can then be withdrawn by
// permissioned accounts.
//
// There are two kinds of protocol fees:
//
// - flash loan fees: charged on all flash loans, as a percentage of the amounts lent.
//
// - swap fees: a percentage of the fees charged by Pools when performing swaps. For a number of reasons, including
// swap gas costs and interface simplicity, protocol swap fees are not charged on each individual swap. Rather,
// Pools are expected to keep track of how much they have charged in swap fees, and pay any outstanding debts to the
// Vault when they are joined or exited. This prevents users from joining a Pool with unpaid debt, as well as
// exiting a Pool in debt without first paying their share.
/**
* @dev Returns the current protocol fee module.
*/
function getProtocolFeesCollector() external view returns (IProtocolFeesCollector);
/**
* @dev Safety mechanism to pause most Vault operations in the event of an emergency - typically detection of an
* error in some part of the system.
*
* The Vault can only be paused during an initial time period, after which pausing is forever disabled.
*
* While the contract is paused, the following features are disabled:
* - depositing and transferring internal balance
* - transferring external balance (using the Vault's allowance)
* - swaps
* - joining Pools
* - Asset Manager interactions
*
* Internal Balance can still be withdrawn, and Pools exited.
*/
function setPaused(bool paused) external;
/**
* @dev Returns the Vault's WETH instance.
*/
function WETH() external view returns (IWETH);
// solhint-disable-previous-line func-name-mixedcase
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
interface ISwapRouter {
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint deadline;
uint amountIn;
uint amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
/// @notice Swaps amountIn of one token for as much as possible of another token
/// @param params The parameters necessary for the swap, encoded as ExactInputSingleParams in calldata
/// @return amountOut The amount of the received token
function exactInputSingle(
ExactInputSingleParams calldata params
) external payable returns (uint amountOut);
struct ExactInputParams {
bytes path;
address recipient;
uint deadline;
uint amountIn;
uint amountOutMinimum;
}
/// @notice Swaps amountIn of one token for as much as possible of another along the specified path
/// @param params The parameters necessary for the multi-hop swap, encoded as ExactInputParams in calldata
/// @return amountOut The amount of the received token
function exactInput(
ExactInputParams calldata params
) external payable returns (uint amountOut);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20Upgradeable.sol";
import "./extensions/IERC20MetadataUpgradeable.sol";
import "../../utils/ContextUpgradeable.sol";
import "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* The default value of {decimals} is 18. To select a different value for
* {decimals} you should overload it.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {
__ERC20_init_unchained(name_, symbol_);
}
function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless this function is
* overridden;
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[45] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20Upgradeable.sol";
import "../extensions/draft-IERC20PermitUpgradeable.sol";
import "../../../utils/AddressUpgradeable.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20Upgradeable {
using AddressUpgradeable for address;
function safeTransfer(
IERC20Upgradeable token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20Upgradeable token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20Upgradeable token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20Upgradeable token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20Upgradeable token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20PermitUpgradeable token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (interfaces/IERC4626.sol)
pragma solidity ^0.8.0;
import "../token/ERC20/IERC20Upgradeable.sol";
import "../token/ERC20/extensions/IERC20MetadataUpgradeable.sol";
/**
* @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*
* _Available since v4.7._
*/
interface IERC4626Upgradeable is IERC20Upgradeable, IERC20MetadataUpgradeable {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(
uint256 assets,
address receiver,
address owner
) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(
uint256 shares,
address receiver,
address owner
) external returns (uint256 assets);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library MathUpgradeable {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.15;
import "src/Kernel.sol";
abstract contract ROLESv1 is Module {
// ========= EVENTS ========= //
event RoleGranted(bytes32 indexed role_, address indexed addr_);
event RoleRevoked(bytes32 indexed role_, address indexed addr_);
// ========= ERRORS ========= //
error ROLES_InvalidRole(bytes32 role_);
error ROLES_RequireRole(bytes32 role_);
error ROLES_AddressAlreadyHasRole(address addr_, bytes32 role_);
error ROLES_AddressDoesNotHaveRole(address addr_, bytes32 role_);
error ROLES_RoleDoesNotExist(bytes32 role_);
// ========= STATE ========= //
/// @notice Mapping for if an address has a policy-defined role.
mapping(address => mapping(bytes32 => bool)) public hasRole;
// ========= FUNCTIONS ========= //
/// @notice Function to grant policy-defined roles to some address. Can only be called by admin.
function saveRole(bytes32 role_, address addr_) external virtual;
/// @notice Function to revoke policy-defined roles from some address. Can only be called by admin.
function removeRole(bytes32 role_, address addr_) external virtual;
/// @notice "Modifier" to restrict policy function access to certain addresses with a role.
/// @dev Roles are defined in the policy and granted by the ROLES admin.
function requireRole(bytes32 role_, address caller_) external virtual;
/// @notice Function that checks if role is valid (all lower case)
function ensureValidRole(bytes32 role_) external pure virtual;
}// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.15;
interface IScaledBalanceToken {
/**
* @dev Returns the scaled balance of the user. The scaled balance is the sum of all the
* updated stored balance divided by the reserve's liquidity index at the moment of the update
* @param user The user whose balance is calculated
* @return The scaled balance of the user
*
*/
function scaledBalanceOf(address user) external view returns (uint256);
/**
* @dev Returns the scaled balance of the user and the scaled total supply.
* @param user The address of the user
* @return The scaled balance of the user
* @return The scaled balance and the scaled total supply
*
*/
function getScaledUserBalanceAndSupply(address user) external view returns (uint256, uint256);
/**
* @dev Returns the scaled total supply of the variable debt token. Represents sum(debt/index)
* @return The scaled total supply
*
*/
function scaledTotalSupply() external view returns (uint256);
}// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.15;
import {ILendingPool} from "./ILendingPool.sol";
import {IAaveIncentivesController} from "./IAaveIncentivesController.sol";
/**
* @title IInitializableAToken
* @notice Interface for the initialize function on AToken
* @author Aave
*
*/
interface IInitializableAToken {
/**
* @dev Emitted when an aToken is initialized
* @param underlyingAsset The address of the underlying asset
* @param pool The address of the associated lending pool
* @param treasury The address of the treasury
* @param incentivesController The address of the incentives controller for this aToken
* @param aTokenDecimals the decimals of the underlying
* @param aTokenName the name of the aToken
* @param aTokenSymbol the symbol of the aToken
* @param params A set of encoded parameters for additional initialization
*
*/
event Initialized(
address indexed underlyingAsset,
address indexed pool,
address treasury,
address incentivesController,
uint8 aTokenDecimals,
string aTokenName,
string aTokenSymbol,
bytes params
);
/**
* @dev Initializes the aToken
* @param pool The address of the lending pool where this aToken will be used
* @param treasury The address of the Aave treasury, receiving the fees on this aToken
* @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH)
* @param incentivesController The smart contract managing potential incentives distribution
* @param aTokenDecimals The decimals of the aToken, same as the underlying asset's
* @param aTokenName The name of the aToken
* @param aTokenSymbol The symbol of the aToken
*/
function initialize(
ILendingPool pool,
address treasury,
address underlyingAsset,
IAaveIncentivesController incentivesController,
uint8 aTokenDecimals,
string calldata aTokenName,
string calldata aTokenSymbol,
bytes calldata params
) external;
}// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.15;
pragma experimental ABIEncoderV2;
interface IAaveIncentivesController {
event RewardsAccrued(address indexed user, uint256 amount);
event RewardsClaimed(address indexed user, address indexed to, uint256 amount);
event RewardsClaimed(address indexed user, address indexed to, address indexed claimer, uint256 amount);
event ClaimerSet(address indexed user, address indexed claimer);
/*
* @dev Returns the configuration of the distribution for a certain asset
* @param asset The address of the reference asset of the distribution
* @return The asset index, the emission per second and the last updated timestamp
**/
function getAssetData(address asset) external view returns (uint256, uint256, uint256);
/**
* @dev Whitelists an address to claim the rewards on behalf of another address
* @param user The address of the user
* @param claimer The address of the claimer
*/
function setClaimer(address user, address claimer) external;
/**
* @dev Returns the whitelisted claimer for a certain address (0x0 if not set)
* @param user The address of the user
* @return The claimer address
*/
function getClaimer(address user) external view returns (address);
/**
* @dev Configure assets for a certain rewards emission
* @param assets The assets to incentivize
* @param emissionsPerSecond The emission for each asset
*/
function configureAssets(address[] calldata assets, uint256[] calldata emissionsPerSecond) external;
/**
* @dev Called by the corresponding asset on any update that affects the rewards distribution
* @param user The address of the user
*
*/
function handleActionBefore(address user) external;
/**
* @dev Called by the corresponding asset on any update that affects the rewards distribution
* @param user The address of the user
* @param userBalance The balance of the user of the asset in the lending pool
* @param totalSupply The total supply of the asset in the lending pool
*
*/
function handleActionAfter(address user, uint256 userBalance, uint256 totalSupply) external;
/**
* @dev Returns the total of rewards of an user, already accrued + not yet accrued
* @param user The address of the user
* @return The rewards
*
*/
function getRewardsBalance(address[] calldata assets, address user) external view returns (uint256);
/**
* @dev Claims reward for an user, on all the assets of the lending pool, accumulating the pending rewards
* @param amount Amount of rewards to claim
* @param to Address that will be receiving the rewards
* @return Rewards claimed
*
*/
function claimRewards(address[] calldata assets, uint256 amount, address to) external returns (uint256);
/**
* @dev Claims reward for an user on behalf, on all the assets of the lending pool, accumulating the pending rewards. The caller must
* be whitelisted via "allowClaimOnBehalf" function by the RewardsAdmin role manager
* @param amount Amount of rewards to claim
* @param user Address to check and claim rewards
* @param to Address that will be receiving the rewards
* @return Rewards claimed
*
*/
function claimRewardsOnBehalf(address[] calldata assets, uint256 amount, address user, address to)
external
returns (uint256);
/**
* @dev returns the unclaimed rewards of the user
* @param user the address of the user
* @return the unclaimed user rewards
*/
function getUserUnclaimedRewards(address user) external view returns (uint256);
/**
* @dev returns the unclaimed rewards of the user
* @param user the address of the user
* @param asset The asset to incentivize
* @return the user index for the asset
*/
function getUserAssetData(address user, address asset) external view returns (uint256);
/**
* @dev for backward compatibility with previous implementation of the Incentives controller
*/
function REWARD_TOKEN() external view returns (address);
/**
* @dev for backward compatibility with previous implementation of the Incentives controller
*/
function PRECISION() external view returns (uint8);
/**
* @dev Gets the distribution end timestamp of the emissions
*/
function DISTRIBUTION_END() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
pragma abicoder v2;
struct LockedBalance {
uint256 amount;
uint256 unlockTime;
uint256 multiplier;
uint256 duration;
}
struct EarnedBalance {
uint256 amount;
uint256 unlockTime;
uint256 penalty;
}
struct Reward {
uint256 periodFinish;
uint256 rewardPerSecond;
uint256 lastUpdateTime;
uint256 rewardPerTokenStored;
// tracks already-added balances to handle accrued interest in aToken rewards
// for the stakingToken this value is unused and will always be 0
uint256 balance;
}
struct Balances {
uint256 total; // sum of earnings and lockings; no use when LP and RDNT is different
uint256 unlocked; // RDNT token
uint256 locked; // LP token or RDNT token
uint256 lockedWithMultiplier; // Multiplied locked amount
uint256 earned; // RDNT token
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
pragma abicoder v2;
import "./LockedBalance.sol";
interface IFeeDistribution {
struct RewardData {
address token;
uint256 amount;
}
function addReward(address rewardsToken) external;
function lockedBalances(address user)
external
view
returns (uint256, uint256, uint256, uint256, LockedBalance[] memory);
}// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.15;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IMintableToken is IERC20 {
function mint(address _receiver, uint256 _amount) external returns (bool);
function burn(uint256 _amount) external returns (bool);
function setMinter(address _minter) external returns (bool);
}// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.15;
/**
* @title LendingPoolAddressesProvider contract
* @dev Main registry of addresses part of or connected to the protocol, including permissioned roles
* - Acting also as factory of proxies and admin of those, so with right to change its implementations
* - Owned by the Aave Governance
* @author Aave
*
*/
interface ILendingPoolAddressesProvider {
event MarketIdSet(string newMarketId);
event LendingPoolUpdated(address indexed newAddress);
event ConfigurationAdminUpdated(address indexed newAddress);
event EmergencyAdminUpdated(address indexed newAddress);
event LendingPoolConfiguratorUpdated(address indexed newAddress);
event LendingPoolCollateralManagerUpdated(address indexed newAddress);
event PriceOracleUpdated(address indexed newAddress);
event LendingRateOracleUpdated(address indexed newAddress);
event ProxyCreated(bytes32 id, address indexed newAddress);
event AddressSet(bytes32 id, address indexed newAddress, bool hasProxy);
function getMarketId() external view returns (string memory);
function setMarketId(string calldata marketId) external;
function setAddress(bytes32 id, address newAddress) external;
function setAddressAsProxy(bytes32 id, address impl) external;
function getAddress(bytes32 id) external view returns (address);
function getLendingPool() external view returns (address);
function setLendingPoolImpl(address pool) external;
function getLendingPoolConfigurator() external view returns (address);
function setLendingPoolConfiguratorImpl(address configurator) external;
function getLendingPoolCollateralManager() external view returns (address);
function setLendingPoolCollateralManager(address manager) external;
function getPoolAdmin() external view returns (address);
function setPoolAdmin(address admin) external;
function getEmergencyAdmin() external view returns (address);
function setEmergencyAdmin(address admin) external;
function getPriceOracle() external view returns (address);
function setPriceOracle(address priceOracle) external;
function getLendingRateOracle() external view returns (address);
function setLendingRateOracle(address lendingRateOracle) external;
function getLiquidationFeeTo() external view returns (address);
function setLiquidationFeeTo(address liquidationFeeTo) external;
}// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.15;
library DataTypes {
// refer to the whitepaper, section 1.1 basic concepts for a formal description of these properties.
struct ReserveData {
//stores the reserve configuration
ReserveConfigurationMap configuration;
//the liquidity index. Expressed in ray
uint128 liquidityIndex;
//variable borrow index. Expressed in ray
uint128 variableBorrowIndex;
//the current supply rate. Expressed in ray
uint128 currentLiquidityRate;
//the current variable borrow rate. Expressed in ray
uint128 currentVariableBorrowRate;
//the current stable borrow rate. Expressed in ray
uint128 currentStableBorrowRate;
uint40 lastUpdateTimestamp;
//tokens addresses
address aTokenAddress;
address stableDebtTokenAddress;
address variableDebtTokenAddress;
//address of the interest rate strategy
address interestRateStrategyAddress;
//the id of the reserve. Represents the position in the list of the active reserves
uint8 id;
}
struct ReserveConfigurationMap {
//bit 0-15: LTV
//bit 16-31: Liq. threshold
//bit 32-47: Liq. bonus
//bit 48-55: Decimals
//bit 56: Reserve is active
//bit 57: reserve is frozen
//bit 58: borrowing is enabled
//bit 59: stable rate borrowing enabled
//bit 60-63: reserved
//bit 64-79: reserve factor
uint256 data;
}
struct UserConfigurationMap {
uint256 data;
}
enum InterestRateMode {
NONE,
STABLE,
VARIABLE
}
}// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity >=0.7.0 <0.9.0;
/**
* @dev This is an empty interface used to represent either ERC20-conforming token contracts or ETH (using the zero
* address sentinel value). We're just relying on the fact that `interface` can be used to declare new address-like
* types.
*
* This concept is unrelated to a Pool's Asset Managers.
*/
interface IAsset {
// solhint-disable-previous-line no-empty-blocks
}// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity >=0.7.0 <0.9.0;
interface IAuthorizer {
/**
* @dev Returns true if `account` can perform the action described by `actionId` in the contract `where`.
*/
function canPerform(bytes32 actionId, address account, address where) external view returns (bool);
}// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity >=0.7.0 <0.9.0;
// Inspired by Aave Protocol's IFlashLoanReceiver.
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IFlashLoanRecipient {
/**
* @dev When `flashLoan` is called on the Vault, it invokes the `receiveFlashLoan` hook on the recipient.
*
* At the time of the call, the Vault will have transferred `amounts` for `tokens` to the recipient. Before this
* call returns, the recipient must have transferred `amounts` plus `feeAmounts` for each token back to the
* Vault, or else the entire flash loan will revert.
*
* `userData` is the same value passed in the `IVault.flashLoan` call.
*/
function receiveFlashLoan(
IERC20[] memory tokens,
uint256[] memory amounts,
uint256[] memory feeAmounts,
bytes memory userData
) external;
}// SPDX-License-Identifier: GPL-3.0-or-later
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity >=0.7.0 <0.9.0;
pragma experimental ABIEncoderV2;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IVault.sol";
import "./IAuthorizer.sol";
interface IProtocolFeesCollector {
event SwapFeePercentageChanged(uint256 newSwapFeePercentage);
event FlashLoanFeePercentageChanged(uint256 newFlashLoanFeePercentage);
function withdrawCollectedFees(IERC20[] calldata tokens, uint256[] calldata amounts, address recipient) external;
function setSwapFeePercentage(uint256 newSwapFeePercentage) external;
function setFlashLoanFeePercentage(uint256 newFlashLoanFeePercentage) external;
function getSwapFeePercentage() external view returns (uint256);
function getFlashLoanFeePercentage() external view returns (uint256);
function getCollectedFeeAmounts(IERC20[] memory tokens) external view returns (uint256[] memory feeAmounts);
function getAuthorizer() external view returns (IAuthorizer);
function vault() external view returns (IVault);
}pragma solidity ^0.8.15;
interface IWETH {
function deposit() external payable;
function withdraw(uint256 amount) external;
function balanceOf(address account) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transfer(address to, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
event Approval(address indexed owner, address indexed spender, uint256 amount);
event Transfer(address indexed from, address indexed to, uint256 amount);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20Upgradeable {
/**
* @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);
/**
* @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 `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, 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 `from` to `to` 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 from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20Upgradeable.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20MetadataUpgradeable is IERC20Upgradeable {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20PermitUpgradeable {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}{
"remappings": [
"@openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"@openzeppelin/=lib/openzeppelin-contracts/",
"@solmate/=lib/solmate/src/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"solmate/=lib/solmate/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ALREADY_CALIMED","type":"error"},{"inputs":[],"name":"CALLER_NOT_AAVE","type":"error"},{"inputs":[],"name":"CALLER_NOT_KERNEL","type":"error"},{"inputs":[],"name":"EXCEED_BOOSTED_AMOUNT","type":"error"},{"inputs":[],"name":"EXCEED_MAX_REDEEM","type":"error"},{"inputs":[],"name":"EXCEED_MAX_WITHDRAW","type":"error"},{"inputs":[{"internalType":"uint256","name":"vaultCap","type":"uint256"}],"name":"EXCEED_VAULT_CAP","type":"error"},{"inputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"name":"FEE_PERCENT_TOO_HIGH","type":"error"},{"inputs":[],"name":"INVALID_PARAM","type":"error"},{"inputs":[],"name":"LIMITED_WITHDRAW","type":"error"},{"inputs":[],"name":"NOT_CLAIMABLE","type":"error"},{"inputs":[],"name":"TOO_LOW_DEPOSIT","type":"error"},{"inputs":[],"name":"ZERO_ADDRESS","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"leverager","type":"address"}],"name":"CreditDelegationDisabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"leverager","type":"address"}],"name":"CreditDelegationEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"defaultLockIndex","type":"uint256"}],"name":"DefaultLockIndexUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"depositFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"withdrawFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"compoundFee","type":"uint256"}],"name":"FeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"kernel","type":"address"}],"name":"KernelChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"rewardBaseTokens","type":"address[]"}],"name":"RewardBaseTokensAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"rewardBaseTokens","type":"address[]"}],"name":"RewardBaseTokensRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"vaultCap","type":"uint256"}],"name":"VaultCapUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"WithdrawQueued","type":"event"},{"inputs":[],"name":"AAVE_LENDING_POOL","outputs":[{"internalType":"contract IPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DLP","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LENDING_POOL","outputs":[{"internalType":"contract ILendingPool","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_QUEUE_PER_WALLET","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_QUEUE_PROCESS_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MFD","outputs":[{"internalType":"contract IMultiFeeDistribution","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MULTIPLIER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RDNT","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RDNT_WETH_POOL_ID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROLES","outputs":[{"internalType":"contract ROLESv1","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SWAP_ROUTER","outputs":[{"internalType":"contract ISwapRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VAULT","outputs":[{"internalType":"contract IVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_rewardBaseTokens","type":"address[]"},{"internalType":"bool[]","name":"_isATokens","type":"bool[]"},{"internalType":"uint24[]","name":"_poolFees","type":"uint24[]"},{"internalType":"uint256[]","name":"_swapThresholds","type":"uint256[]"}],"name":"addRewardBaseTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"boostDLP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"boostedDLP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract Kernel","name":"_kernel","type":"address"}],"name":"changeKernel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimableDLP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"compound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"configureDependencies","outputs":[{"internalType":"Keycode[]","name":"dependencies","type":"bytes5[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultLockIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assets","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ICreditDelegationToken","name":"_token","type":"address"},{"internalType":"address","name":"_leverager","type":"address"}],"name":"disableCreditDelegation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ICreditDelegationToken","name":"_token","type":"address"},{"internalType":"address","name":"_leverager","type":"address"}],"name":"enableCreditDelegation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"premium","type":"uint256"},{"internalType":"address","name":"initiator","type":"address"},{"internalType":"bytes","name":"params","type":"bytes"}],"name":"executeOperation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fee","outputs":[{"internalType":"uint256","name":"depositFee","type":"uint256"},{"internalType":"uint256","name":"withdrawFee","type":"uint256"},{"internalType":"uint256","name":"compoundFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFee","outputs":[{"internalType":"uint256","name":"depositFee","type":"uint256"},{"internalType":"uint256","name":"withdrawFee","type":"uint256"},{"internalType":"uint256","name":"compoundFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRewardBaseTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Kernel","name":"_kernel","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"kernel","outputs":[{"internalType":"contract Kernel","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"processWithdrawalQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"queuedDLP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_shares","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_rewardBaseTokens","type":"address[]"}],"name":"removeRewardBaseTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requestPermissions","outputs":[{"components":[{"internalType":"Keycode","name":"keycode","type":"bytes5"},{"internalType":"bytes4","name":"funcSelector","type":"bytes4"}],"internalType":"struct Permissions[]","name":"requests","type":"tuple[]"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewards","outputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"isAToken","type":"bool"},{"internalType":"uint24","name":"poolFee","type":"uint24"},{"internalType":"uint256","name":"swapThreshold","type":"uint256"},{"internalType":"uint256","name":"pending","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_defaultLockIndex","type":"uint256"}],"name":"setDefaultLockIndex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositFee","type":"uint256"},{"internalType":"uint256","name":"_withdrawFee","type":"uint256"},{"internalType":"uint256","name":"_compoundFee","type":"uint256"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_vaultCap","type":"uint256"}],"name":"setVaultCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"unboostDLP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vaultCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_assets","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawForLeverager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"withdrawTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalQueueIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"withdrawalQueues","outputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint32","name":"createdAt","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"withdrawalsOf","outputs":[{"internalType":"uint256[]","name":"indexes","type":"uint256[]"},{"components":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint32","name":"createdAt","type":"uint32"}],"internalType":"struct DLPVault.WithdrawalQueue[]","name":"queues","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60806040523480156200001157600080fd5b506200001c62000022565b620000e4565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161015620000e2576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b615c0880620000f46000396000f3fe6080604052600436106104355760003560e01c80637743b6d311610229578063ba0876521161012e578063d568f2f2116100b6578063e318efca1161007a578063e318efca14610d3b578063ef8b30f714610c15578063f0f5907d14610d5b578063f301af4214610d7b578063f69e204614610dd757600080fd5b8063d568f2f214610ca7578063d905777e14610cbc578063dd62ed3e14610cdc578063ddca3f4314610cfc578063de92bd8314610d1b57600080fd5b8063c63d75b6116100fd578063c63d75b614610bf3578063c6e6f59214610c15578063ce96cb7714610c35578063ced72f8714610c55578063d4aae0c414610c8757600080fd5b8063ba08765214610b6b578063c4d66de814610b8b578063c5f3950414610bab578063c600589314610bcb57600080fd5b80639edf1004116101b1578063b3d7f6b911610180578063b3d7f6b914610abb578063b41b208e14610adb578063b460af9414610b03578063b4dcfc7714610b23578063b9db677814610b4b57600080fd5b80639edf100414610a2b578063a457c2d714610a53578063a9059cbb14610a73578063ad5c464814610a9357600080fd5b80638b56046b116101f85780638b56046b1461098c578063923cb952146109b45780639459b875146109d457806394bf804d146109f657806395d89b4114610a1657600080fd5b80637743b6d3146108e3578063787739cf14610939578063857d22fb1461096157806389f5bc711461097657600080fd5b806338d52e0f1161033a5780634cdad506116102c257806361b6b6441161028657806361b6b6441461084257806361d027b3146108585780636b72f9c9146108785780636e553f651461088d57806370a08231146108ad57600080fd5b80634cdad506146104a25780634dab861c146107ca578063586c54a7146107e05780635924be70146108005780635b65b9ab1461082257600080fd5b80633f9be262116103095780633f9be26214610714578063402d267d14610742578063411557d1146107625780634657b36c1461078a57806349df728c146107aa57600080fd5b806338d52e0f1461069657806339509351146106c85780633c1bda09146106e85780633dfac49a146106fe57600080fd5b8063171a88d2116103bd57806323b872dd1161038c57806323b872dd146105f45780632a5daaa714610614578063313ce56714610634578063329d8c9a14610660578063379607f51461067657600080fd5b8063171a88d21461057657806318160ddd146105aa5780631b11d0ff146105bf57806322f3e2d4146105df57600080fd5b806308b182531161040457806308b18253146104c257806308ede0ae146104e4578063095ea7b3146105045780630a28a477146105345780630ddfb4ce1461055457600080fd5b806301e1d11414610441578063059f8b161461046957806306fdde031461048057806307a2d13a146104a257600080fd5b3661043c57005b600080fd5b34801561044d57600080fd5b50610456610dec565b6040519081526020015b60405180910390f35b34801561047557600080fd5b50610456620f424081565b34801561048c57600080fd5b50610495610efd565b60405161046091906151c0565b3480156104ae57600080fd5b506104566104bd3660046151d3565b610f8f565b3480156104ce57600080fd5b506104e26104dd366004615238565b610fa2565b005b3480156104f057600080fd5b506104e26104ff366004615311565b611201565b34801561051057600080fd5b5061052461051f36600461534a565b611367565b6040519015158152602001610460565b34801561054057600080fd5b5061045661054f3660046151d3565b61137f565b34801561056057600080fd5b5061056961138c565b6040516104609190615376565b34801561058257600080fd5b506104567f32df62dc3aed2cd6224193052ce665dc181658410002000000000000000003bd81565b3480156105b657600080fd5b50603554610456565b3480156105cb57600080fd5b506105246105da3660046153c3565b61144f565b3480156105eb57600080fd5b50610524611917565b34801561060057600080fd5b5061052461060f36600461546d565b611984565b34801561062057600080fd5b506104e261062f3660046151d3565b6119aa565b34801561064057600080fd5b50606554600160a01b900460ff1660405160ff9091168152602001610460565b34801561066c57600080fd5b50610456609b5481565b34801561068257600080fd5b506104e26106913660046151d3565b611b6e565b3480156106a257600080fd5b506065546001600160a01b03165b6040516001600160a01b039091168152602001610460565b3480156106d457600080fd5b506105246106e336600461534a565b611cb8565b3480156106f457600080fd5b50610456609a5481565b34801561070a57600080fd5b50610456609c5481565b34801561072057600080fd5b5061073461072f3660046154ae565b611cda565b604051610460929190615506565b34801561074e57600080fd5b5061045661075d3660046154ae565b611e88565b34801561076e57600080fd5b506106b073ba12222222228d8ba445958a75a0704d566bf2c881565b34801561079657600080fd5b506104e26107a53660046154ae565b611ea6565b3480156107b657600080fd5b506104e26107c53660046154ae565b611f26565b3480156107d657600080fd5b5061045660a45481565b3480156107ec57600080fd5b506104e26107fb366004615311565b6120b9565b34801561080c57600080fd5b506108156121b9565b604051610460919061558e565b34801561082e57600080fd5b506104e261083d3660046155f1565b6121fe565b34801561084e57600080fd5b5061045660a35481565b34801561086457600080fd5b506099546106b0906001600160a01b031681565b34801561088457600080fd5b50610456601e81565b34801561089957600080fd5b506104566108a836600461561d565b61234d565b3480156108b957600080fd5b506104566108c83660046154ae565b6001600160a01b031660009081526033602052604090205490565b3480156108ef57600080fd5b506109036108fe3660046151d3565b6123e4565b604080516001600160a01b0395861681526020810194909452919093169082015263ffffffff9091166060820152608001610460565b34801561094557600080fd5b506106b0733082cc23568ea640225c2467653db90e9250aaa081565b34801561096d57600080fd5b506104e2612432565b34801561098257600080fd5b5061045660a25481565b34801561099857600080fd5b506106b073794a61358d6845594f94dc1db02a252b5b4814ad81565b3480156109c057600080fd5b506097546106b0906001600160a01b031681565b3480156109e057600080fd5b506109e96125fa565b6040516104609190615642565b348015610a0257600080fd5b50610456610a1136600461561d565b6127fc565b348015610a2257600080fd5b50610495612859565b348015610a3757600080fd5b506106b07376ba3ec5f5adbf1c58c91e86502232317eea72de81565b348015610a5f57600080fd5b50610524610a6e36600461534a565b612868565b348015610a7f57600080fd5b50610524610a8e36600461534a565b6128ee565b348015610a9f57600080fd5b506106b07382af49447d8a07e3bd95bd0d56f35241523fbab181565b348015610ac757600080fd5b50610456610ad63660046151d3565b6128fc565b348015610ae757600080fd5b506106b07332df62dc3aed2cd6224193052ce665dc1816584181565b348015610b0f57600080fd5b50610456610b1e366004615684565b612909565b348015610b2f57600080fd5b506106b073f4b1486dd74d07706052a33d31d7c0aafd0659e181565b348015610b5757600080fd5b506104e2610b6636600461534a565b61297d565b348015610b7757600080fd5b50610456610b86366004615684565b612a66565b348015610b9757600080fd5b506104e2610ba63660046154ae565b612ad2565b348015610bb757600080fd5b506104e2610bc63660046151d3565b612d99565b348015610bd757600080fd5b506106b073e592427a0aece92de3edee1f18e0157c0586156481565b348015610bff57600080fd5b50610456610c0e3660046154ae565b5060001990565b348015610c2157600080fd5b50610456610c303660046151d3565b612e3c565b348015610c4157600080fd5b50610456610c503660046154ae565b612e49565b348015610c6157600080fd5b50609e54609f5460a0545b60408051938452602084019290925290820152606001610460565b348015610c9357600080fd5b506098546106b0906001600160a01b031681565b348015610cb357600080fd5b50610456600581565b348015610cc857600080fd5b50610456610cd73660046154ae565b612e6d565b348015610ce857600080fd5b50610456610cf7366004615311565b612e8b565b348015610d0857600080fd5b50609e54609f5460a054610c6c92919083565b348015610d2757600080fd5b506104e2610d363660046151d3565b612eb6565b348015610d4757600080fd5b506104e2610d563660046156c6565b612fb3565b348015610d6757600080fd5b506104e2610d763660046151d3565b61322d565b348015610d8757600080fd5b50610d9b610d963660046151d3565b6132c4565b604080516001600160a01b039096168652931515602086015262ffffff909216928401929092526060830191909152608082015260a001610460565b348015610de357600080fd5b506104e261331a565b6000609c5460a354610dfe919061571e565b6040516370a0823160e01b81523060048201527332df62dc3aed2cd6224193052ce665dc18165841906370a0823190602401602060405180830381865afa158015610e4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e719190615736565b604051630dd59a7360e31b81523060048201527376ba3ec5f5adbf1c58c91e86502232317eea72de90636eacd39890602401602060405180830381865afa158015610ec0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee49190615736565b610eee919061571e565b610ef8919061574f565b905090565b606060368054610f0c90615766565b80601f0160208091040260200160405190810160405280929190818152602001828054610f3890615766565b8015610f855780601f10610f5a57610100808354040283529160200191610f85565b820191906000526020600020905b815481529060010190602001808311610f6857829003601f168201915b5050505050905090565b6000610f9c8260006135aa565b92915050565b60975460405163d09a20c560e01b81526001600160a01b039091169063d09a20c590610fd29033906004016157a0565b600060405180830381600087803b158015610fec57600080fd5b505af1158015611000573d6000803e3d6000fd5b508992505050858114611026576040516322ee6ae760e01b815260040160405180910390fd5b808414611046576040516322ee6ae760e01b815260040160405180910390fd5b808214611066576040516322ee6ae760e01b815260040160405180910390fd5b60005b818110156111bc57609d6040518060a001604052808c8c85818110611090576110906157c2565b90506020020160208101906110a591906154ae565b6001600160a01b031681526020018a8a858181106110c5576110c56157c2565b90506020020160208101906110da91906157e6565b151581526020018888858181106110f3576110f36157c2565b90506020020160208101906111089190615803565b62ffffff168152602001868685818110611124576111246157c2565b602090810292909201358352506000918101829052835460018181018655948352918190208351600390930201805491840151604085015162ffffff16600160a81b0262ffffff60a81b19911515600160a01b026001600160a81b03199094166001600160a01b0390951694909417929092179190911691909117815560608201518184015560809091015160029091015501611069565b507f8a668144efe1ae25527720ce2843db64f0577657ae64bd0902061d1cb58782cd89896040516111ee929190615828565b60405180910390a1505050505050505050565b60975460405163d09a20c560e01b81526001600160a01b039091169063d09a20c5906112319033906004016157a0565b600060405180830381600087803b15801561124b57600080fd5b505af115801561125f573d6000803e3d6000fd5b505060975460405163d09a20c560e01b81528493506001600160a01b03909116915063d09a20c590611295908490600401615876565b600060405180830381600087803b1580156112af57600080fd5b505af11580156112c3573d6000803e3d6000fd5b5050604051630c04a8a160e41b81526001600160a01b03858116600483015260001960248301528616925063c04a8a109150604401600060405180830381600087803b15801561131257600080fd5b505af1158015611326573d6000803e3d6000fd5b50506040516001600160a01b038086169350861691507f3389dbdf78ba1516178c55bba63439922fdfd24a97aa224f0463be8a8d25783490600090a3505050565b6000336113758185856135dd565b5060019392505050565b6000610f9c826001613701565b609d5460609060008167ffffffffffffffff8111156113ad576113ad61589c565b6040519080825280602002602001820160405280156113d6578160200160208202803683370190505b50905060005b8281101561144857609d81815481106113f7576113f76157c2565b600091825260209091206003909102015482516001600160a01b0390911690839083908110611428576114286157c2565b6001600160a01b03909216602092830291909101909101526001016113dc565b5092915050565b60003373794a61358d6845594f94dc1db02a252b5b4814ad14611485576040516316eb572b60e21b815260040160405180910390fd5b60975460405163d09a20c560e01b815285916001600160a01b03169063d09a20c5906114b5908490600401615876565b600060405180830381600087803b1580156114cf57600080fd5b505af11580156114e3573d6000803e3d6000fd5b5050604051636eb1769f60e11b815230600482015273f4b1486dd74d07706052a33d31d7c0aafd0659e160248201526001600160a01b038b16925063dd62ed3e9150604401602060405180830381865afa158015611545573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115699190615736565b60000361159a5761159a6001600160a01b03891673f4b1486dd74d07706052a33d31d7c0aafd0659e1600019613733565b604051636eb1769f60e11b815230600482015273794a61358d6845594f94dc1db02a252b5b4814ad60248201526001600160a01b0389169063dd62ed3e90604401602060405180830381865afa1580156115f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061161c9190615736565b60000361164d5761164d6001600160a01b03891673794a61358d6845594f94dc1db02a252b5b4814ad600019613733565b60405163573ade8160e01b81526001600160a01b0389166004820152602481018890526002604482018190523060648301529073f4b1486dd74d07706052a33d31d7c0aafd0659e19063573ade81906084016020604051808303816000875af11580156116be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e29190615736565b5073f4b1486dd74d07706052a33d31d7c0aafd0659e16369328dec8a6117088a8c61571e565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201523060448201526064016020604051808303816000875af1158015611759573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177d9190615736565b5060008061178d8688018861561d565b909250905073f4b1486dd74d07706052a33d31d7c0aafd0659e16369328dec8c61188b6117ba8d8761574f565b8c6001600160a01b031663b29c55bc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061181c91906158b2565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015611862573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118869190615736565b61381e565b6040516001600160e01b031960e085901b1681526001600160a01b039283166004820152602481019190915290841660448201526064016020604051808303816000875af11580156118e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119059190615736565b5060019b9a5050505050505050505050565b60985460405163e52223bb60e01b81523060048201526000916001600160a01b03169063e52223bb90602401602060405180830381865afa158015611960573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef891906158cf565b600033611992858285613834565b61199d8585856138a8565b60019150505b9392505050565b60975460405163d09a20c560e01b81526001600160a01b039091169063d09a20c5906119da9033906004016157a0565b600060405180830381600087803b1580156119f457600080fd5b505af1158015611a08573d6000803e3d6000fd5b50505050609c54811115611a2f57604051631d1cac5d60e01b815260040160405180910390fd5b80609c6000828254611a41919061574f565b925050819055508060a36000828254611a5a919061571e565b909155505060a180546040805160808101825233808252602080830187815283850183815263ffffffff42811660608701908152600189018a556000998a529551600389027faadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f649878810180546001600160a01b039384166001600160a01b031990911617905593517faadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f64987985015591517faadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f64987a909301805496518216600160a01b026001600160c01b031990971693909216929092179490941790935590855260a5905292209091611b6991908390613a5316565b505050565b60a2548110611b90576040516312738dcf60e11b815260040160405180910390fd5b600060a18281548110611ba557611ba56157c2565b60009182526020808320600390920290910180546001600160a01b0316835260a59091526040909120909150611bdb9083613a5f565b611bf85760405163987a6c5b60e01b815260040160405180910390fd5b806001015460a36000828254611c0e919061574f565b9091555050600181015460a48054600090611c2a90849061574f565b909155505060028101546001820154611c64917332df62dc3aed2cd6224193052ce665dc18165841916001600160a01b0390911690613a6b565b600281015460018201546040805185815260208101929092526001600160a01b03909216917f4ec90e965519d92681267467f775ada5bd214aa92c0dc93d90a5e880ce9ed026910160405180910390a25050565b600033611375818585611ccb8383612e8b565b611cd5919061571e565b6135dd565b6001600160a01b038116600090815260a560205260408120606091829190611d0182613a9b565b90508067ffffffffffffffff811115611d1c57611d1c61589c565b604051908082528060200260200182016040528015611d45578160200160208202803683370190505b5093508067ffffffffffffffff811115611d6157611d6161589c565b604051908082528060200260200182016040528015611db357816020015b604080516080810182526000808252602080830182905292820181905260608201528252600019909201910181611d7f5790505b50925060005b81811015611e80576000611dcd8483613aa5565b905080868381518110611de257611de26157c2565b60200260200101818152505060a18181548110611e0157611e016157c2565b60009182526020918290206040805160808101825260039390930290910180546001600160a01b0390811684526001820154948401949094526002015492831690820152600160a01b90910463ffffffff1660608201528551869084908110611e6c57611e6c6157c2565b602090810291909101015250600101611db9565b505050915091565b6000611e92613ab1565b611e9d576000610f9c565b60001992915050565b6098546001600160a01b03163314611ed157604051635532616b60e11b815260040160405180910390fd5b609880546001600160a01b0319166001600160a01b0383169081179091556040519081527f5836616dd5fc96ee348d862205c768f70efb839d75c0290d5404ff02974637f2906020015b60405180910390a150565b60975460405163d09a20c560e01b81526001600160a01b039091169063d09a20c590611f569033906004016157a0565b600060405180830381600087803b158015611f7057600080fd5b505af1158015611f84573d6000803e3d6000fd5b5050506001600160a01b0382169050611ff057604051600090339047908381818185875af1925050503d8060008114611fd9576040519150601f19603f3d011682016040523d82523d6000602084013e611fde565b606091505b5050905080611fec57600080fd5b5050565b6040516370a0823160e01b815230600482015281906000906001600160a01b038316906370a0823190602401602060405180830381865afa158015612039573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061205d9190615736565b90507332df62dc3aed2cd6224193052ce665dc18165840196001600160a01b0383160161209c5761208c612432565b60a454612099908261574f565b90505b8015611b6957611b696001600160a01b0383163383613a6b565b50565b60975460405163d09a20c560e01b81526001600160a01b039091169063d09a20c5906120e99033906004016157a0565b600060405180830381600087803b15801561210357600080fd5b505af1158015612117573d6000803e3d6000fd5b5050604051630c04a8a160e41b81526001600160a01b038481166004830152600060248301528516925063c04a8a109150604401600060405180830381600087803b15801561216557600080fd5b505af1158015612179573d6000803e3d6000fd5b50506040516001600160a01b038085169350851691507faf7290e22bf6a0b754ef3e443a7d60791c11cbe6f6a254ec921e4210ca00e8a590600090a35050565b604080516000808252602082019092526060916121f8565b60408051808201909152600080825260208201528152602001906001900390816121d15790505b50905090565b60975460405163d09a20c560e01b81526001600160a01b039091169063d09a20c59061222e9033906004016157a0565b600060405180830381600087803b15801561224857600080fd5b505af115801561225c573d6000803e3d6000fd5b505050506002620f42406122709190615902565b831061229757604051633598a32360e01b8152600481018490526024015b60405180910390fd5b6122a56002620f4240615902565b82106122c757604051633598a32360e01b81526004810183905260240161228e565b6122d56002620f4240615902565b81106122f757604051633598a32360e01b81526004810182905260240161228e565b609e839055609f82905560a081905560408051848152602081018490529081018290527f509d432c4ab40e3eb039ee95fea93be8de6c751efa87aed5e51c7202b0dd8e09906060015b60405180910390a1505050565b600061235761331a565b61236083613acb565b9250609a548361236e610dec565b612378919061571e565b11156123ad5782612387610dec565b612391919061571e565b60405163f5a67bb160e01b815260040161228e91815260200190565b60006123b98484613b35565b9050806000036123dc5760405163a9eae1c960e01b815260040160405180910390fd5b6119a3613ba8565b60a181815481106123f457600080fd5b60009182526020909120600390910201805460018201546002909201546001600160a01b03918216935090811690600160a01b900463ffffffff1684565b604051638f40aab160e01b815230600482015260006024820152600160448201527376ba3ec5f5adbf1c58c91e86502232317eea72de90638f40aab1906064016020604051808303816000875af1158015612491573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124b59190615736565b5060a4546040516370a0823160e01b8152306004820152600091907332df62dc3aed2cd6224193052ce665dc18165841906370a0823190602401602060405180830381865afa15801561250c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125309190615736565b61253a919061574f565b60a15490915060005b601e8110801561255457508160a254105b15611b6957600060a160a25481548110612570576125706157c2565b600091825260209182902060408051608081018252600390930290910180546001600160a01b03908116845260018201549484018590526002909101549081169183019190915263ffffffff600160a01b90910416606082015291508410156125d95750505050565b6020015160a480548201905560a28054600190810190915593039201612543565b604080516002808252606080830184529260208301908036833701905050905064524f4c455360d81b81600081518110612636576126366157c2565b6001600160d81b03199092166020928302919091019091015261265e64545253525960d81b90565b81600181518110612671576126716157c2565b6001600160d81b03199092166020928302919091019091015260985481516001600160a01b039091169063b4dc00b49083906000906126b2576126b26157c2565b60200260200101516040518263ffffffff1660e01b81526004016126e691906001600160d81b031991909116815260200190565b602060405180830381865afa158015612703573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061272791906158b2565b609780546001600160a01b0319166001600160a01b03928316179055609854825191169063b4dc00b49083906001908110612764576127646157c2565b60200260200101516040518263ffffffff1660e01b815260040161279891906001600160d81b031991909116815260200190565b602060405180830381865afa1580156127b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d991906158b2565b609980546001600160a01b0319166001600160a01b039290921691909117905590565b600061280661331a565b61280f83613c40565b9250826000036128325760405163a9eae1c960e01b815260040160405180910390fd5b600061283e8484613cc1565b9050609a5461284b610dec565b11156123dc57612391610dec565b606060378054610f0c90615766565b600033816128768286612e8b565b9050838110156128d65760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b606482015260840161228e565b6128e382868684036135dd565b506001949350505050565b6000336113758185856138a8565b6000610f9c8260016135aa565b600061291361331a565b6099546001600160a01b031633146129325761292f8483613cdb565b93505b61293b82612e49565b84111561295b576040516389a37b0560e01b815260040160405180910390fd5b60006129668561137f565b90506129753385858885613d6c565b949350505050565b60975460405163d09a20c560e01b815233916001600160a01b03169063d09a20c5906129ad908490600401615876565b600060405180830381600087803b1580156129c757600080fd5b505af11580156129db573d6000803e3d6000fd5b5050604051632e1a7d4d60e01b8152600481018590527376ba3ec5f5adbf1c58c91e86502232317eea72de9250632e1a7d4d9150602401600060405180830381600087803b158015612a2c57600080fd5b505af1158015612a40573d6000803e3d6000fd5b50611b699250733082cc23568ea640225c2467653db90e9250aaa0915085905084613a6b565b6000612a7061331a565b6099546001600160a01b03163314612a8f57612a8c8483613f7f565b93505b612a9882612e6d565b841115612ab857604051638192d26960e01b815260040160405180910390fd5b6000612ac385610f8f565b90506129753385858489613d6c565b600054610100900460ff1615808015612af25750600054600160ff909116105b80612b0c5750303b158015612b0c575060005460ff166001145b612b6f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161228e565b6000805460ff191660011790558015612b92576000805461ff0019166101001790555b609880546001600160a01b0319166001600160a01b0384161790556000609b55604051636eb1769f60e11b81523060048201527376ba3ec5f5adbf1c58c91e86502232317eea72de60248201527332df62dc3aed2cd6224193052ce665dc181658419063dd62ed3e90604401602060405180830381865afa158015612c1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c3f9190615736565b600003612c7b57612c7b7332df62dc3aed2cd6224193052ce665dc181658417376ba3ec5f5adbf1c58c91e86502232317eea72de600019613733565b60405163f7ad360160e01b8152600060048201527376ba3ec5f5adbf1c58c91e86502232317eea72de9063f7ad360190602401600060405180830381600087803b158015612cc857600080fd5b505af1158015612cdc573d6000803e3d6000fd5b50505050612d33604051806040016040528060118152602001701498591a585d19481113140815985d5b1d607a1b815250604051806040016040528060088152602001670524144542d444c560c41b815250613fe6565b612d507332df62dc3aed2cd6224193052ce665dc18165841614017565b8015611fec576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b60975460405163d09a20c560e01b81526001600160a01b039091169063d09a20c590612dc99033906004016157a0565b600060405180830381600087803b158015612de357600080fd5b505af1158015612df7573d6000803e3d6000fd5b5050505080609c6000828254612e0d919061571e565b90915550612e3390507332df62dc3aed2cd6224193052ce665dc18165841333084614047565b6120b68161407f565b6000610f9c826000613701565b6001600160a01b038116600090815260336020526040812054610f9c9060006135aa565b6001600160a01b038116600090815260336020526040812054610f9c565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b60975460405163d09a20c560e01b81526001600160a01b039091169063d09a20c590612ee69033906004016157a0565b600060405180830381600087803b158015612f0057600080fd5b505af1158015612f14573d6000803e3d6000fd5b505050609b82905550604051636fa75e6d60e01b8152600481018290527376ba3ec5f5adbf1c58c91e86502232317eea72de90636fa75e6d90602401600060405180830381600087803b158015612f6a57600080fd5b505af1158015612f7e573d6000803e3d6000fd5b505050507fb8311beac77e34e8b0ee25610f33e4425fe1480349f7281ad9b2f84e5d55c0ce81604051611f1b91815260200190565b60975460405163d09a20c560e01b81526001600160a01b039091169063d09a20c590612fe39033906004016157a0565b600060405180830381600087803b158015612ffd57600080fd5b505af1158015613011573d6000803e3d6000fd5b5083925060009150505b818110156131fb57609d5460005b818110156131f157858584818110613043576130436157c2565b905060200201602081019061305891906154ae565b6001600160a01b0316609d8281548110613074576130746157c2565b60009182526020909120600390910201546001600160a01b0316036131e957609d6130a060018461574f565b815481106130b0576130b06157c2565b9060005260206000209060030201609d82815481106130d1576130d16157c2565b60009182526020909120825460039092020180546001600160a01b031981166001600160a01b039093169283178255835460ff600160a01b91829004161515026001600160a81b031990911690921791909117808255825462ffffff600160a81b91829004160262ffffff60a81b19909116178155600180830154818301556002928301549290910191909155609d9061316b908461574f565b8154811061317b5761317b6157c2565b60009182526020822060039091020180546001600160c01b03191681556001810182905560020155609d8054806131b4576131b4615924565b60008281526020812060036000199093019283020180546001600160c01b0319168155600181018290556002015590556131f1565b600101613029565b505060010161301b565b507f17f582422cfcc57818c51be740311f8ee88583876caf220373ad31cac097bc528383604051612340929190615828565b60975460405163d09a20c560e01b81526001600160a01b039091169063d09a20c59061325d9033906004016157a0565b600060405180830381600087803b15801561327757600080fd5b505af115801561328b573d6000803e3d6000fd5b505050609a829055506040518181527f29bbb39c738a5da8394774006ed1b0ff5a7b1051f5c1e7b4142b5f36950418ed90602001611f1b565b609d81815481106132d457600080fd5b60009182526020909120600390910201805460018201546002909201546001600160a01b0382169350600160a01b820460ff1692600160a81b90920462ffffff16919085565b60355460000361332657565b609d5460008167ffffffffffffffff8111156133445761334461589c565b60405190808252806020026020018201604052801561336d578160200160208202803683370190505b50905060005b8281101561342d57609d818154811061338e5761338e6157c2565b60009182526020909120600390910201546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156133e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134089190615736565b82828151811061341a5761341a6157c2565b6020908102919091010152600101613373565b507376ba3ec5f5adbf1c58c91e86502232317eea72de637fd7d06261345061138c565b6040518263ffffffff1660e01b815260040161346c9190615376565b600060405180830381600087803b15801561348657600080fd5b505af115801561349a573d6000803e3d6000fd5b5050505060005b82811015613591576000609d82815481106134be576134be6157c2565b9060005260206000209060030201905060008383815181106134e2576134e26157c2565b602090810291909101015182546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015613534573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135589190615736565b613562919061574f565b90508015613587576002820180548201905561357e82826141d9565b61358782614227565b50506001016134a1565b5061359a614565565b6135a2612432565b611fec613ba8565b6000806135b660355490565b905080156135d7576135d26135c9610dec565b85908386614884565b612975565b83612975565b6001600160a01b03831661363f5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161228e565b6001600160a01b0382166136a05760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161228e565b6001600160a01b0383811660008181526034602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60008061370d60355490565b905083158061371a575080155b6135d7576135d28161372a610dec565b86919086614884565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015613784573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137a89190615736565b6137b2919061571e565b6040516001600160a01b03851660248201526044810182905290915061381890859063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526148df565b50505050565b600081831061382d57816119a3565b5090919050565b60006138408484612e8b565b90506000198114613818578181101561389b5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161228e565b61381884848484036135dd565b6001600160a01b03831661390c5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b606482015260840161228e565b6001600160a01b03821661396e5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b606482015260840161228e565b6001600160a01b038316600090815260336020526040902054818110156139e65760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b606482015260840161228e565b6001600160a01b0380851660008181526033602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90613a469086815260200190565b60405180910390a3613818565b60006119a383836149b1565b60006119a38383614a00565b6040516001600160a01b038316602482015260448101829052611b6990849063a9059cbb60e01b906064016137e1565b6000610f9c825490565b60006119a38383614af3565b600080613abc610dec565b1180610ef85750506035541590565b609e546000908103613adb575090565b609e54600090620f424090613af0908561593a565b613afa9190615902565b609954909150613b2b907332df62dc3aed2cd6224193052ce665dc181658419033906001600160a01b031684614047565b6119a3818461574f565b6000613b4082611e88565b831115613b8f5760405162461bcd60e51b815260206004820152601e60248201527f455243343632363a206465706f736974206d6f7265207468616e206d61780000604482015260640161228e565b6000613b9a84612e3c565b90506119a333848684614b1d565b6040516370a0823160e01b81523060048201526000907332df62dc3aed2cd6224193052ce665dc18165841906370a0823190602401602060405180830381865afa158015613bfa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c1e9190615736565b905060a3548111156120b6576120b660a35482613c3b919061574f565b61407f565b609e546000908103613c50575090565b6000620f4240609e60000154613c65856128fc565b613c6f919061593a565b613c799190615902565b90506000613c868261137f565b609954909150613cb7907332df62dc3aed2cd6224193052ce665dc181658419033906001600160a01b031685614047565b612975818561574f565b600080613ccd846128fc565b90506119a333848387614b1d565b609f546000908103613cee575081610f9c565b6000620f4240609e60010154613d038661137f565b613d0d919061593a565b613d179190615902565b90506000613d24826128fc565b9050336001600160a01b03851614613d4157613d41843384613834565b609954613d599085906001600160a01b0316846138a8565b613d63818661574f565b95945050505050565b6001600160a01b038416613d935760405163538ba4f960e01b815260040160405180910390fd5b6001600160a01b038516600090815260a5602052604090206005613db682613a9b565b10613dd457604051634d42eda560e01b815260040160405180910390fd5b836001600160a01b0316866001600160a01b031614613df857613df8848784613834565b613e028483614b9b565b8260a36000828254613e14919061571e565b909155505060a18054604080516080810182526001600160a01b03808b168252602082018881528a821693830193845263ffffffff428116606085019081526001870188556000979097529251600386027faadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f649878810180549285166001600160a01b03199093169290921790915590517faadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f64987982015592517faadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f64987a909301805495518316600160a01b026001600160c01b0319909616939091169290921793909317905590613f219083908390613a5316565b5060408051828152602081018690529081018490526001600160a01b0380871691888216918a16907f29ee677b5632db3d11fb8c8d0ff321bb6a3c2d20af84dcbae26c1751189e17299060600160405180910390a450505050505050565b609f546000908103613f92575081610f9c565b609f54600090620f424090613fa7908661593a565b613fb19190615902565b9050336001600160a01b03841614613fce57613fce833383613834565b609954613cb79084906001600160a01b0316836138a8565b600054610100900460ff1661400d5760405162461bcd60e51b815260040161228e90615959565b611fec8282614ccf565b600054610100900460ff1661403e5760405162461bcd60e51b815260040161228e90615959565b6120b681614d0f565b6040516001600160a01b03808516602483015283166044820152606481018290526138189085906323b872dd60e01b906084016137e1565b7376ba3ec5f5adbf1c58c91e86502232317eea72de6001600160a01b031663b36b9ffd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156140d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140f591906158b2565b6001600160a01b031663d9cdd5136040518163ffffffff1660e01b8152600401602060405180830381865afa158015614132573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141569190615736565b8110156141605750565b609b54604051631ba724c760e21b81526004810183905230602482015260448101919091527376ba3ec5f5adbf1c58c91e86502232317eea72de90636e9c931c90606401600060405180830381600087803b1580156141be57600080fd5b505af11580156141d2573d6000803e3d6000fd5b5050505050565b60a054600090620f4240906141ee908461593a565b6141f89190615902565b90508015611b695760028301805482900390556099548354611b69916001600160a01b03918216911683613a6b565b80600101548160020154101561423a5750565b80546000908190600160a01b900460ff16156143d45760028301548354614282916001600160a01b039091169073f4b1486dd74d07706052a33d31d7c0aafd0659e190613733565b8254604080516358b50cef60e11b815290516001600160a01b039092169163b16a19de916004808201926020929091908290030181865afa1580156142cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142ef91906158b2565b60028401546040516001600160a01b03831660248201526044810191909152306064820152909250600090819073f4b1486dd74d07706052a33d31d7c0aafd0659e19060840160408051601f198184030181529181526020820180516001600160e01b0316631a4ca37b60e21b1790525161436a91906159a4565b6000604051808303816000865af19150503d80600081146143a7576040519150601f19603f3d011682016040523d82523d6000602084013e6143ac565b606091505b509150915081156141d257808060200190518101906143cb9190615736565b925050506143ea565b5050805460028201546001600160a01b03909116905b600060028401557382af49447d8a07e3bd95bd0d56f35241523fbab0196001600160a01b0383160161441b57505050565b6144436001600160a01b03831673e592427a0aece92de3edee1f18e0157c0586156483613733565b60408051610100810182526001600160a01b0384811682527382af49447d8a07e3bd95bd0d56f35241523fbab1602083019081528654600160a81b900462ffffff9081168486019081523060608601908152426080870190815260a08701898152600060c0890181815260e08a01918252995163414bf38960e01b815289518916600482015296518816602488015293519094166044860152905185166064850152516084840152905160a4830152935160c482015292511660e48301529073e592427a0aece92de3edee1f18e0157c058615649063414bf38990610104016020604051808303816000875af1158015614541573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141d29190615736565b6040516370a0823160e01b81523060048201526000907382af49447d8a07e3bd95bd0d56f35241523fbab1906370a0823190602401602060405180830381865afa1580156145b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145db9190615736565b9050662386f26fc100008110156145ef5750565b60405163095ea7b360e01b815273ba12222222228d8ba445958a75a0704d566bf2c86004820152602481018290527382af49447d8a07e3bd95bd0d56f35241523fbab19063095ea7b3906044016020604051808303816000875af115801561465b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061467f91906158cf565b50604080516002808252606082018352600092602083019080368337019050509050733082cc23568ea640225c2467653db90e9250aaa0816000815181106146c9576146c96157c2565b60200260200101906001600160a01b031690816001600160a01b0316815250507382af49447d8a07e3bd95bd0d56f35241523fbab181600181518110614711576147116157c2565b6001600160a01b03929092166020928302919091018201526040805160028082526060820183526000939192909183019080368337019050509050600081600081518110614761576147616157c2565b6020026020010181815250508281600181518110614781576147816157c2565b6020026020010181815250506147ba60405180608001604052806060815260200160608152602001606081526020016000151581525090565b82815260208082018390526040516147da916001918591600091016159c0565b60408051601f19818403018152918152828101919091525163172b958560e31b815273ba12222222228d8ba445958a75a0704d566bf2c89063b95cac289061484c907f32df62dc3aed2cd6224193052ce665dc181658410002000000000000000003bd903090819087906004016159ef565b600060405180830381600087803b15801561486657600080fd5b505af115801561487a573d6000803e3d6000fd5b5050505050505050565b600080614892868686614d94565b905060018360028111156148a8576148a8615aae565b1480156148c55750600084806148c0576148c06158ec565b868809115b15613d63576148d560018261571e565b9695505050505050565b6000614934826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614e439092919063ffffffff16565b805190915015611b69578080602001905181019061495291906158cf565b611b695760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161228e565b60008181526001830160205260408120546149f857508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610f9c565b506000610f9c565b60008181526001830160205260408120548015614ae9576000614a2460018361574f565b8554909150600090614a389060019061574f565b9050818114614a9d576000866000018281548110614a5857614a586157c2565b9060005260206000200154905080876000018481548110614a7b57614a7b6157c2565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080614aae57614aae615924565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610f9c565b6000915050610f9c565b6000826000018281548110614b0a57614b0a6157c2565b9060005260206000200154905092915050565b606554614b35906001600160a01b0316853085614047565b614b3f8382614e52565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d78484604051614b8d929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b038216614bfb5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b606482015260840161228e565b6001600160a01b03821660009081526033602052604090205481811015614c6f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b606482015260840161228e565b6001600160a01b03831660008181526033602090815260408083208686039055603580548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b600054610100900460ff16614cf65760405162461bcd60e51b815260040161228e90615959565b6036614d028382615b12565b506037611b698282615b12565b600054610100900460ff16614d365760405162461bcd60e51b815260040161228e90615959565b600080614d4283614f13565b9150915081614d52576012614d54565b805b606580546001600160a01b039095166001600160a01b031960ff93909316600160a01b02929092166001600160a81b031990951694909417179092555050565b6000808060001985870985870292508281108382030391505080600003614dce57838281614dc457614dc46158ec565b04925050506119a3565b808411614dda57600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60606129758484600085614fef565b6001600160a01b038216614ea85760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640161228e565b8060356000828254614eba919061571e565b90915550506001600160a01b0382166000818152603360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b60408051600481526024810182526020810180516001600160e01b031663313ce56760e01b17905290516000918291829182916001600160a01b03871691614f5a916159a4565b600060405180830381855afa9150503d8060008114614f95576040519150601f19603f3d011682016040523d82523d6000602084013e614f9a565b606091505b5091509150818015614fae57506020815110155b15614fe257600081806020019051810190614fc99190615736565b905060ff8111614fe0576001969095509350505050565b505b5060009485945092505050565b6060824710156150505760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161228e565b600080866001600160a01b0316858760405161506c91906159a4565b60006040518083038185875af1925050503d80600081146150a9576040519150601f19603f3d011682016040523d82523d6000602084013e6150ae565b606091505b50915091506150bf878383876150ca565b979650505050505050565b60608315615139578251600003615132576001600160a01b0385163b6151325760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161228e565b5081612975565b612975838381511561514e5781518083602001fd5b8060405162461bcd60e51b815260040161228e91906151c0565b60005b8381101561518357818101518382015260200161516b565b838111156138185750506000910152565b600081518084526151ac816020860160208601615168565b601f01601f19169290920160200192915050565b6020815260006119a36020830184615194565b6000602082840312156151e557600080fd5b5035919050565b60008083601f8401126151fe57600080fd5b50813567ffffffffffffffff81111561521657600080fd5b6020830191508360208260051b850101111561523157600080fd5b9250929050565b6000806000806000806000806080898b03121561525457600080fd5b883567ffffffffffffffff8082111561526c57600080fd5b6152788c838d016151ec565b909a50985060208b013591508082111561529157600080fd5b61529d8c838d016151ec565b909850965060408b01359150808211156152b657600080fd5b6152c28c838d016151ec565b909650945060608b01359150808211156152db57600080fd5b506152e88b828c016151ec565b999c989b5096995094979396929594505050565b6001600160a01b03811681146120b657600080fd5b6000806040838503121561532457600080fd5b823561532f816152fc565b9150602083013561533f816152fc565b809150509250929050565b6000806040838503121561535d57600080fd5b8235615368816152fc565b946020939093013593505050565b6020808252825182820181905260009190848201906040850190845b818110156153b75783516001600160a01b031683529284019291840191600101615392565b50909695505050505050565b60008060008060008060a087890312156153dc57600080fd5b86356153e7816152fc565b955060208701359450604087013593506060870135615405816152fc565b9250608087013567ffffffffffffffff8082111561542257600080fd5b818901915089601f83011261543657600080fd5b81358181111561544557600080fd5b8a602082850101111561545757600080fd5b6020830194508093505050509295509295509295565b60008060006060848603121561548257600080fd5b833561548d816152fc565b9250602084013561549d816152fc565b929592945050506040919091013590565b6000602082840312156154c057600080fd5b81356119a3816152fc565b600081518084526020808501945080840160005b838110156154fb578151875295820195908201906001016154df565b509495945050505050565b60006040808352615519818401866154cb565b83810360208581019190915285518083528682019282019060005b8181101561558057845180516001600160a01b039081168552858201518686015287820151168785015260609081015163ffffffff169084015293830193608090920191600101615534565b509098975050505050505050565b602080825282518282018190526000919060409081850190868401855b828110156155e457815180516001600160d81b03191685528601516001600160e01b0319168685015292840192908501906001016155ab565b5091979650505050505050565b60008060006060848603121561560657600080fd5b505081359360208301359350604090920135919050565b6000806040838503121561563057600080fd5b82359150602083013561533f816152fc565b6020808252825182820181905260009190848201906040850190845b818110156153b75783516001600160d81b0319168352928401929184019160010161565e565b60008060006060848603121561569957600080fd5b8335925060208401356156ab816152fc565b915060408401356156bb816152fc565b809150509250925092565b600080602083850312156156d957600080fd5b823567ffffffffffffffff8111156156f057600080fd5b6156fc858286016151ec565b90969095509350505050565b634e487b7160e01b600052601160045260246000fd5b6000821982111561573157615731615708565b500190565b60006020828403121561574857600080fd5b5051919050565b60008282101561576157615761615708565b500390565b600181811c9082168061577a57607f821691505b60208210810361579a57634e487b7160e01b600052602260045260246000fd5b50919050565b6430b236b4b760d91b81526001600160a01b0391909116602082015260400190565b634e487b7160e01b600052603260045260246000fd5b80151581146120b657600080fd5b6000602082840312156157f857600080fd5b81356119a3816157d8565b60006020828403121561581557600080fd5b813562ffffff811681146119a357600080fd5b60208082528181018390526000908460408401835b8681101561586b578235615850816152fc565b6001600160a01b03168252918301919083019060010161583d565b509695505050505050565b683632bb32b930b3b2b960b91b81526001600160a01b0391909116602082015260400190565b634e487b7160e01b600052604160045260246000fd5b6000602082840312156158c457600080fd5b81516119a3816152fc565b6000602082840312156158e157600080fd5b81516119a3816157d8565b634e487b7160e01b600052601260045260246000fd5b60008261591f57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603160045260246000fd5b600081600019048311821515161561595457615954615708565b500290565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b600082516159b6818460208701615168565b9190910192915050565b60ff841681526060602082015260006159dc60608301856154cb565b905060ff83166040830152949350505050565b8481526000602060018060a01b038087168285015280861660408501526080606085015261010084018551608080870152818151808452610120880191508583019350600092505b80831015615a5957835185168252928501926001929092019190850190615a37565b50848801519450607f199350838782030160a0880152615a7981866154cb565b94505050506040850151818584030160c0860152615a978382615194565b92505050606084015161586b60e085018215159052565b634e487b7160e01b600052602160045260246000fd5b601f821115611b6957600081815260208120601f850160051c81016020861015615aeb5750805b601f850160051c820191505b81811015615b0a57828155600101615af7565b505050505050565b815167ffffffffffffffff811115615b2c57615b2c61589c565b615b4081615b3a8454615766565b84615ac4565b602080601f831160018114615b755760008415615b5d5750858301515b600019600386901b1c1916600185901b178555615b0a565b600085815260208120601f198616915b82811015615ba457888601518255948401946001909101908401615b85565b5085821015615bc25787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea26469706673582212200b920128d6a77dc7a3ad6ad48074d2b799982932154fae1101630b1d80278c6164736f6c634300080f0033
Deployed Bytecode
0x6080604052600436106104355760003560e01c80637743b6d311610229578063ba0876521161012e578063d568f2f2116100b6578063e318efca1161007a578063e318efca14610d3b578063ef8b30f714610c15578063f0f5907d14610d5b578063f301af4214610d7b578063f69e204614610dd757600080fd5b8063d568f2f214610ca7578063d905777e14610cbc578063dd62ed3e14610cdc578063ddca3f4314610cfc578063de92bd8314610d1b57600080fd5b8063c63d75b6116100fd578063c63d75b614610bf3578063c6e6f59214610c15578063ce96cb7714610c35578063ced72f8714610c55578063d4aae0c414610c8757600080fd5b8063ba08765214610b6b578063c4d66de814610b8b578063c5f3950414610bab578063c600589314610bcb57600080fd5b80639edf1004116101b1578063b3d7f6b911610180578063b3d7f6b914610abb578063b41b208e14610adb578063b460af9414610b03578063b4dcfc7714610b23578063b9db677814610b4b57600080fd5b80639edf100414610a2b578063a457c2d714610a53578063a9059cbb14610a73578063ad5c464814610a9357600080fd5b80638b56046b116101f85780638b56046b1461098c578063923cb952146109b45780639459b875146109d457806394bf804d146109f657806395d89b4114610a1657600080fd5b80637743b6d3146108e3578063787739cf14610939578063857d22fb1461096157806389f5bc711461097657600080fd5b806338d52e0f1161033a5780634cdad506116102c257806361b6b6441161028657806361b6b6441461084257806361d027b3146108585780636b72f9c9146108785780636e553f651461088d57806370a08231146108ad57600080fd5b80634cdad506146104a25780634dab861c146107ca578063586c54a7146107e05780635924be70146108005780635b65b9ab1461082257600080fd5b80633f9be262116103095780633f9be26214610714578063402d267d14610742578063411557d1146107625780634657b36c1461078a57806349df728c146107aa57600080fd5b806338d52e0f1461069657806339509351146106c85780633c1bda09146106e85780633dfac49a146106fe57600080fd5b8063171a88d2116103bd57806323b872dd1161038c57806323b872dd146105f45780632a5daaa714610614578063313ce56714610634578063329d8c9a14610660578063379607f51461067657600080fd5b8063171a88d21461057657806318160ddd146105aa5780631b11d0ff146105bf57806322f3e2d4146105df57600080fd5b806308b182531161040457806308b18253146104c257806308ede0ae146104e4578063095ea7b3146105045780630a28a477146105345780630ddfb4ce1461055457600080fd5b806301e1d11414610441578063059f8b161461046957806306fdde031461048057806307a2d13a146104a257600080fd5b3661043c57005b600080fd5b34801561044d57600080fd5b50610456610dec565b6040519081526020015b60405180910390f35b34801561047557600080fd5b50610456620f424081565b34801561048c57600080fd5b50610495610efd565b60405161046091906151c0565b3480156104ae57600080fd5b506104566104bd3660046151d3565b610f8f565b3480156104ce57600080fd5b506104e26104dd366004615238565b610fa2565b005b3480156104f057600080fd5b506104e26104ff366004615311565b611201565b34801561051057600080fd5b5061052461051f36600461534a565b611367565b6040519015158152602001610460565b34801561054057600080fd5b5061045661054f3660046151d3565b61137f565b34801561056057600080fd5b5061056961138c565b6040516104609190615376565b34801561058257600080fd5b506104567f32df62dc3aed2cd6224193052ce665dc181658410002000000000000000003bd81565b3480156105b657600080fd5b50603554610456565b3480156105cb57600080fd5b506105246105da3660046153c3565b61144f565b3480156105eb57600080fd5b50610524611917565b34801561060057600080fd5b5061052461060f36600461546d565b611984565b34801561062057600080fd5b506104e261062f3660046151d3565b6119aa565b34801561064057600080fd5b50606554600160a01b900460ff1660405160ff9091168152602001610460565b34801561066c57600080fd5b50610456609b5481565b34801561068257600080fd5b506104e26106913660046151d3565b611b6e565b3480156106a257600080fd5b506065546001600160a01b03165b6040516001600160a01b039091168152602001610460565b3480156106d457600080fd5b506105246106e336600461534a565b611cb8565b3480156106f457600080fd5b50610456609a5481565b34801561070a57600080fd5b50610456609c5481565b34801561072057600080fd5b5061073461072f3660046154ae565b611cda565b604051610460929190615506565b34801561074e57600080fd5b5061045661075d3660046154ae565b611e88565b34801561076e57600080fd5b506106b073ba12222222228d8ba445958a75a0704d566bf2c881565b34801561079657600080fd5b506104e26107a53660046154ae565b611ea6565b3480156107b657600080fd5b506104e26107c53660046154ae565b611f26565b3480156107d657600080fd5b5061045660a45481565b3480156107ec57600080fd5b506104e26107fb366004615311565b6120b9565b34801561080c57600080fd5b506108156121b9565b604051610460919061558e565b34801561082e57600080fd5b506104e261083d3660046155f1565b6121fe565b34801561084e57600080fd5b5061045660a35481565b34801561086457600080fd5b506099546106b0906001600160a01b031681565b34801561088457600080fd5b50610456601e81565b34801561089957600080fd5b506104566108a836600461561d565b61234d565b3480156108b957600080fd5b506104566108c83660046154ae565b6001600160a01b031660009081526033602052604090205490565b3480156108ef57600080fd5b506109036108fe3660046151d3565b6123e4565b604080516001600160a01b0395861681526020810194909452919093169082015263ffffffff9091166060820152608001610460565b34801561094557600080fd5b506106b0733082cc23568ea640225c2467653db90e9250aaa081565b34801561096d57600080fd5b506104e2612432565b34801561098257600080fd5b5061045660a25481565b34801561099857600080fd5b506106b073794a61358d6845594f94dc1db02a252b5b4814ad81565b3480156109c057600080fd5b506097546106b0906001600160a01b031681565b3480156109e057600080fd5b506109e96125fa565b6040516104609190615642565b348015610a0257600080fd5b50610456610a1136600461561d565b6127fc565b348015610a2257600080fd5b50610495612859565b348015610a3757600080fd5b506106b07376ba3ec5f5adbf1c58c91e86502232317eea72de81565b348015610a5f57600080fd5b50610524610a6e36600461534a565b612868565b348015610a7f57600080fd5b50610524610a8e36600461534a565b6128ee565b348015610a9f57600080fd5b506106b07382af49447d8a07e3bd95bd0d56f35241523fbab181565b348015610ac757600080fd5b50610456610ad63660046151d3565b6128fc565b348015610ae757600080fd5b506106b07332df62dc3aed2cd6224193052ce665dc1816584181565b348015610b0f57600080fd5b50610456610b1e366004615684565b612909565b348015610b2f57600080fd5b506106b073f4b1486dd74d07706052a33d31d7c0aafd0659e181565b348015610b5757600080fd5b506104e2610b6636600461534a565b61297d565b348015610b7757600080fd5b50610456610b86366004615684565b612a66565b348015610b9757600080fd5b506104e2610ba63660046154ae565b612ad2565b348015610bb757600080fd5b506104e2610bc63660046151d3565b612d99565b348015610bd757600080fd5b506106b073e592427a0aece92de3edee1f18e0157c0586156481565b348015610bff57600080fd5b50610456610c0e3660046154ae565b5060001990565b348015610c2157600080fd5b50610456610c303660046151d3565b612e3c565b348015610c4157600080fd5b50610456610c503660046154ae565b612e49565b348015610c6157600080fd5b50609e54609f5460a0545b60408051938452602084019290925290820152606001610460565b348015610c9357600080fd5b506098546106b0906001600160a01b031681565b348015610cb357600080fd5b50610456600581565b348015610cc857600080fd5b50610456610cd73660046154ae565b612e6d565b348015610ce857600080fd5b50610456610cf7366004615311565b612e8b565b348015610d0857600080fd5b50609e54609f5460a054610c6c92919083565b348015610d2757600080fd5b506104e2610d363660046151d3565b612eb6565b348015610d4757600080fd5b506104e2610d563660046156c6565b612fb3565b348015610d6757600080fd5b506104e2610d763660046151d3565b61322d565b348015610d8757600080fd5b50610d9b610d963660046151d3565b6132c4565b604080516001600160a01b039096168652931515602086015262ffffff909216928401929092526060830191909152608082015260a001610460565b348015610de357600080fd5b506104e261331a565b6000609c5460a354610dfe919061571e565b6040516370a0823160e01b81523060048201527332df62dc3aed2cd6224193052ce665dc18165841906370a0823190602401602060405180830381865afa158015610e4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e719190615736565b604051630dd59a7360e31b81523060048201527376ba3ec5f5adbf1c58c91e86502232317eea72de90636eacd39890602401602060405180830381865afa158015610ec0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ee49190615736565b610eee919061571e565b610ef8919061574f565b905090565b606060368054610f0c90615766565b80601f0160208091040260200160405190810160405280929190818152602001828054610f3890615766565b8015610f855780601f10610f5a57610100808354040283529160200191610f85565b820191906000526020600020905b815481529060010190602001808311610f6857829003601f168201915b5050505050905090565b6000610f9c8260006135aa565b92915050565b60975460405163d09a20c560e01b81526001600160a01b039091169063d09a20c590610fd29033906004016157a0565b600060405180830381600087803b158015610fec57600080fd5b505af1158015611000573d6000803e3d6000fd5b508992505050858114611026576040516322ee6ae760e01b815260040160405180910390fd5b808414611046576040516322ee6ae760e01b815260040160405180910390fd5b808214611066576040516322ee6ae760e01b815260040160405180910390fd5b60005b818110156111bc57609d6040518060a001604052808c8c85818110611090576110906157c2565b90506020020160208101906110a591906154ae565b6001600160a01b031681526020018a8a858181106110c5576110c56157c2565b90506020020160208101906110da91906157e6565b151581526020018888858181106110f3576110f36157c2565b90506020020160208101906111089190615803565b62ffffff168152602001868685818110611124576111246157c2565b602090810292909201358352506000918101829052835460018181018655948352918190208351600390930201805491840151604085015162ffffff16600160a81b0262ffffff60a81b19911515600160a01b026001600160a81b03199094166001600160a01b0390951694909417929092179190911691909117815560608201518184015560809091015160029091015501611069565b507f8a668144efe1ae25527720ce2843db64f0577657ae64bd0902061d1cb58782cd89896040516111ee929190615828565b60405180910390a1505050505050505050565b60975460405163d09a20c560e01b81526001600160a01b039091169063d09a20c5906112319033906004016157a0565b600060405180830381600087803b15801561124b57600080fd5b505af115801561125f573d6000803e3d6000fd5b505060975460405163d09a20c560e01b81528493506001600160a01b03909116915063d09a20c590611295908490600401615876565b600060405180830381600087803b1580156112af57600080fd5b505af11580156112c3573d6000803e3d6000fd5b5050604051630c04a8a160e41b81526001600160a01b03858116600483015260001960248301528616925063c04a8a109150604401600060405180830381600087803b15801561131257600080fd5b505af1158015611326573d6000803e3d6000fd5b50506040516001600160a01b038086169350861691507f3389dbdf78ba1516178c55bba63439922fdfd24a97aa224f0463be8a8d25783490600090a3505050565b6000336113758185856135dd565b5060019392505050565b6000610f9c826001613701565b609d5460609060008167ffffffffffffffff8111156113ad576113ad61589c565b6040519080825280602002602001820160405280156113d6578160200160208202803683370190505b50905060005b8281101561144857609d81815481106113f7576113f76157c2565b600091825260209091206003909102015482516001600160a01b0390911690839083908110611428576114286157c2565b6001600160a01b03909216602092830291909101909101526001016113dc565b5092915050565b60003373794a61358d6845594f94dc1db02a252b5b4814ad14611485576040516316eb572b60e21b815260040160405180910390fd5b60975460405163d09a20c560e01b815285916001600160a01b03169063d09a20c5906114b5908490600401615876565b600060405180830381600087803b1580156114cf57600080fd5b505af11580156114e3573d6000803e3d6000fd5b5050604051636eb1769f60e11b815230600482015273f4b1486dd74d07706052a33d31d7c0aafd0659e160248201526001600160a01b038b16925063dd62ed3e9150604401602060405180830381865afa158015611545573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115699190615736565b60000361159a5761159a6001600160a01b03891673f4b1486dd74d07706052a33d31d7c0aafd0659e1600019613733565b604051636eb1769f60e11b815230600482015273794a61358d6845594f94dc1db02a252b5b4814ad60248201526001600160a01b0389169063dd62ed3e90604401602060405180830381865afa1580156115f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061161c9190615736565b60000361164d5761164d6001600160a01b03891673794a61358d6845594f94dc1db02a252b5b4814ad600019613733565b60405163573ade8160e01b81526001600160a01b0389166004820152602481018890526002604482018190523060648301529073f4b1486dd74d07706052a33d31d7c0aafd0659e19063573ade81906084016020604051808303816000875af11580156116be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116e29190615736565b5073f4b1486dd74d07706052a33d31d7c0aafd0659e16369328dec8a6117088a8c61571e565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201523060448201526064016020604051808303816000875af1158015611759573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177d9190615736565b5060008061178d8688018861561d565b909250905073f4b1486dd74d07706052a33d31d7c0aafd0659e16369328dec8c61188b6117ba8d8761574f565b8c6001600160a01b031663b29c55bc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156117f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061181c91906158b2565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015611862573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118869190615736565b61381e565b6040516001600160e01b031960e085901b1681526001600160a01b039283166004820152602481019190915290841660448201526064016020604051808303816000875af11580156118e1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119059190615736565b5060019b9a5050505050505050505050565b60985460405163e52223bb60e01b81523060048201526000916001600160a01b03169063e52223bb90602401602060405180830381865afa158015611960573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ef891906158cf565b600033611992858285613834565b61199d8585856138a8565b60019150505b9392505050565b60975460405163d09a20c560e01b81526001600160a01b039091169063d09a20c5906119da9033906004016157a0565b600060405180830381600087803b1580156119f457600080fd5b505af1158015611a08573d6000803e3d6000fd5b50505050609c54811115611a2f57604051631d1cac5d60e01b815260040160405180910390fd5b80609c6000828254611a41919061574f565b925050819055508060a36000828254611a5a919061571e565b909155505060a180546040805160808101825233808252602080830187815283850183815263ffffffff42811660608701908152600189018a556000998a529551600389027faadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f649878810180546001600160a01b039384166001600160a01b031990911617905593517faadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f64987985015591517faadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f64987a909301805496518216600160a01b026001600160c01b031990971693909216929092179490941790935590855260a5905292209091611b6991908390613a5316565b505050565b60a2548110611b90576040516312738dcf60e11b815260040160405180910390fd5b600060a18281548110611ba557611ba56157c2565b60009182526020808320600390920290910180546001600160a01b0316835260a59091526040909120909150611bdb9083613a5f565b611bf85760405163987a6c5b60e01b815260040160405180910390fd5b806001015460a36000828254611c0e919061574f565b9091555050600181015460a48054600090611c2a90849061574f565b909155505060028101546001820154611c64917332df62dc3aed2cd6224193052ce665dc18165841916001600160a01b0390911690613a6b565b600281015460018201546040805185815260208101929092526001600160a01b03909216917f4ec90e965519d92681267467f775ada5bd214aa92c0dc93d90a5e880ce9ed026910160405180910390a25050565b600033611375818585611ccb8383612e8b565b611cd5919061571e565b6135dd565b6001600160a01b038116600090815260a560205260408120606091829190611d0182613a9b565b90508067ffffffffffffffff811115611d1c57611d1c61589c565b604051908082528060200260200182016040528015611d45578160200160208202803683370190505b5093508067ffffffffffffffff811115611d6157611d6161589c565b604051908082528060200260200182016040528015611db357816020015b604080516080810182526000808252602080830182905292820181905260608201528252600019909201910181611d7f5790505b50925060005b81811015611e80576000611dcd8483613aa5565b905080868381518110611de257611de26157c2565b60200260200101818152505060a18181548110611e0157611e016157c2565b60009182526020918290206040805160808101825260039390930290910180546001600160a01b0390811684526001820154948401949094526002015492831690820152600160a01b90910463ffffffff1660608201528551869084908110611e6c57611e6c6157c2565b602090810291909101015250600101611db9565b505050915091565b6000611e92613ab1565b611e9d576000610f9c565b60001992915050565b6098546001600160a01b03163314611ed157604051635532616b60e11b815260040160405180910390fd5b609880546001600160a01b0319166001600160a01b0383169081179091556040519081527f5836616dd5fc96ee348d862205c768f70efb839d75c0290d5404ff02974637f2906020015b60405180910390a150565b60975460405163d09a20c560e01b81526001600160a01b039091169063d09a20c590611f569033906004016157a0565b600060405180830381600087803b158015611f7057600080fd5b505af1158015611f84573d6000803e3d6000fd5b5050506001600160a01b0382169050611ff057604051600090339047908381818185875af1925050503d8060008114611fd9576040519150601f19603f3d011682016040523d82523d6000602084013e611fde565b606091505b5050905080611fec57600080fd5b5050565b6040516370a0823160e01b815230600482015281906000906001600160a01b038316906370a0823190602401602060405180830381865afa158015612039573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061205d9190615736565b90507332df62dc3aed2cd6224193052ce665dc18165840196001600160a01b0383160161209c5761208c612432565b60a454612099908261574f565b90505b8015611b6957611b696001600160a01b0383163383613a6b565b50565b60975460405163d09a20c560e01b81526001600160a01b039091169063d09a20c5906120e99033906004016157a0565b600060405180830381600087803b15801561210357600080fd5b505af1158015612117573d6000803e3d6000fd5b5050604051630c04a8a160e41b81526001600160a01b038481166004830152600060248301528516925063c04a8a109150604401600060405180830381600087803b15801561216557600080fd5b505af1158015612179573d6000803e3d6000fd5b50506040516001600160a01b038085169350851691507faf7290e22bf6a0b754ef3e443a7d60791c11cbe6f6a254ec921e4210ca00e8a590600090a35050565b604080516000808252602082019092526060916121f8565b60408051808201909152600080825260208201528152602001906001900390816121d15790505b50905090565b60975460405163d09a20c560e01b81526001600160a01b039091169063d09a20c59061222e9033906004016157a0565b600060405180830381600087803b15801561224857600080fd5b505af115801561225c573d6000803e3d6000fd5b505050506002620f42406122709190615902565b831061229757604051633598a32360e01b8152600481018490526024015b60405180910390fd5b6122a56002620f4240615902565b82106122c757604051633598a32360e01b81526004810183905260240161228e565b6122d56002620f4240615902565b81106122f757604051633598a32360e01b81526004810182905260240161228e565b609e839055609f82905560a081905560408051848152602081018490529081018290527f509d432c4ab40e3eb039ee95fea93be8de6c751efa87aed5e51c7202b0dd8e09906060015b60405180910390a1505050565b600061235761331a565b61236083613acb565b9250609a548361236e610dec565b612378919061571e565b11156123ad5782612387610dec565b612391919061571e565b60405163f5a67bb160e01b815260040161228e91815260200190565b60006123b98484613b35565b9050806000036123dc5760405163a9eae1c960e01b815260040160405180910390fd5b6119a3613ba8565b60a181815481106123f457600080fd5b60009182526020909120600390910201805460018201546002909201546001600160a01b03918216935090811690600160a01b900463ffffffff1684565b604051638f40aab160e01b815230600482015260006024820152600160448201527376ba3ec5f5adbf1c58c91e86502232317eea72de90638f40aab1906064016020604051808303816000875af1158015612491573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124b59190615736565b5060a4546040516370a0823160e01b8152306004820152600091907332df62dc3aed2cd6224193052ce665dc18165841906370a0823190602401602060405180830381865afa15801561250c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125309190615736565b61253a919061574f565b60a15490915060005b601e8110801561255457508160a254105b15611b6957600060a160a25481548110612570576125706157c2565b600091825260209182902060408051608081018252600390930290910180546001600160a01b03908116845260018201549484018590526002909101549081169183019190915263ffffffff600160a01b90910416606082015291508410156125d95750505050565b6020015160a480548201905560a28054600190810190915593039201612543565b604080516002808252606080830184529260208301908036833701905050905064524f4c455360d81b81600081518110612636576126366157c2565b6001600160d81b03199092166020928302919091019091015261265e64545253525960d81b90565b81600181518110612671576126716157c2565b6001600160d81b03199092166020928302919091019091015260985481516001600160a01b039091169063b4dc00b49083906000906126b2576126b26157c2565b60200260200101516040518263ffffffff1660e01b81526004016126e691906001600160d81b031991909116815260200190565b602060405180830381865afa158015612703573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061272791906158b2565b609780546001600160a01b0319166001600160a01b03928316179055609854825191169063b4dc00b49083906001908110612764576127646157c2565b60200260200101516040518263ffffffff1660e01b815260040161279891906001600160d81b031991909116815260200190565b602060405180830381865afa1580156127b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d991906158b2565b609980546001600160a01b0319166001600160a01b039290921691909117905590565b600061280661331a565b61280f83613c40565b9250826000036128325760405163a9eae1c960e01b815260040160405180910390fd5b600061283e8484613cc1565b9050609a5461284b610dec565b11156123dc57612391610dec565b606060378054610f0c90615766565b600033816128768286612e8b565b9050838110156128d65760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b606482015260840161228e565b6128e382868684036135dd565b506001949350505050565b6000336113758185856138a8565b6000610f9c8260016135aa565b600061291361331a565b6099546001600160a01b031633146129325761292f8483613cdb565b93505b61293b82612e49565b84111561295b576040516389a37b0560e01b815260040160405180910390fd5b60006129668561137f565b90506129753385858885613d6c565b949350505050565b60975460405163d09a20c560e01b815233916001600160a01b03169063d09a20c5906129ad908490600401615876565b600060405180830381600087803b1580156129c757600080fd5b505af11580156129db573d6000803e3d6000fd5b5050604051632e1a7d4d60e01b8152600481018590527376ba3ec5f5adbf1c58c91e86502232317eea72de9250632e1a7d4d9150602401600060405180830381600087803b158015612a2c57600080fd5b505af1158015612a40573d6000803e3d6000fd5b50611b699250733082cc23568ea640225c2467653db90e9250aaa0915085905084613a6b565b6000612a7061331a565b6099546001600160a01b03163314612a8f57612a8c8483613f7f565b93505b612a9882612e6d565b841115612ab857604051638192d26960e01b815260040160405180910390fd5b6000612ac385610f8f565b90506129753385858489613d6c565b600054610100900460ff1615808015612af25750600054600160ff909116105b80612b0c5750303b158015612b0c575060005460ff166001145b612b6f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840161228e565b6000805460ff191660011790558015612b92576000805461ff0019166101001790555b609880546001600160a01b0319166001600160a01b0384161790556000609b55604051636eb1769f60e11b81523060048201527376ba3ec5f5adbf1c58c91e86502232317eea72de60248201527332df62dc3aed2cd6224193052ce665dc181658419063dd62ed3e90604401602060405180830381865afa158015612c1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c3f9190615736565b600003612c7b57612c7b7332df62dc3aed2cd6224193052ce665dc181658417376ba3ec5f5adbf1c58c91e86502232317eea72de600019613733565b60405163f7ad360160e01b8152600060048201527376ba3ec5f5adbf1c58c91e86502232317eea72de9063f7ad360190602401600060405180830381600087803b158015612cc857600080fd5b505af1158015612cdc573d6000803e3d6000fd5b50505050612d33604051806040016040528060118152602001701498591a585d19481113140815985d5b1d607a1b815250604051806040016040528060088152602001670524144542d444c560c41b815250613fe6565b612d507332df62dc3aed2cd6224193052ce665dc18165841614017565b8015611fec576000805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b60975460405163d09a20c560e01b81526001600160a01b039091169063d09a20c590612dc99033906004016157a0565b600060405180830381600087803b158015612de357600080fd5b505af1158015612df7573d6000803e3d6000fd5b5050505080609c6000828254612e0d919061571e565b90915550612e3390507332df62dc3aed2cd6224193052ce665dc18165841333084614047565b6120b68161407f565b6000610f9c826000613701565b6001600160a01b038116600090815260336020526040812054610f9c9060006135aa565b6001600160a01b038116600090815260336020526040812054610f9c565b6001600160a01b03918216600090815260346020908152604080832093909416825291909152205490565b60975460405163d09a20c560e01b81526001600160a01b039091169063d09a20c590612ee69033906004016157a0565b600060405180830381600087803b158015612f0057600080fd5b505af1158015612f14573d6000803e3d6000fd5b505050609b82905550604051636fa75e6d60e01b8152600481018290527376ba3ec5f5adbf1c58c91e86502232317eea72de90636fa75e6d90602401600060405180830381600087803b158015612f6a57600080fd5b505af1158015612f7e573d6000803e3d6000fd5b505050507fb8311beac77e34e8b0ee25610f33e4425fe1480349f7281ad9b2f84e5d55c0ce81604051611f1b91815260200190565b60975460405163d09a20c560e01b81526001600160a01b039091169063d09a20c590612fe39033906004016157a0565b600060405180830381600087803b158015612ffd57600080fd5b505af1158015613011573d6000803e3d6000fd5b5083925060009150505b818110156131fb57609d5460005b818110156131f157858584818110613043576130436157c2565b905060200201602081019061305891906154ae565b6001600160a01b0316609d8281548110613074576130746157c2565b60009182526020909120600390910201546001600160a01b0316036131e957609d6130a060018461574f565b815481106130b0576130b06157c2565b9060005260206000209060030201609d82815481106130d1576130d16157c2565b60009182526020909120825460039092020180546001600160a01b031981166001600160a01b039093169283178255835460ff600160a01b91829004161515026001600160a81b031990911690921791909117808255825462ffffff600160a81b91829004160262ffffff60a81b19909116178155600180830154818301556002928301549290910191909155609d9061316b908461574f565b8154811061317b5761317b6157c2565b60009182526020822060039091020180546001600160c01b03191681556001810182905560020155609d8054806131b4576131b4615924565b60008281526020812060036000199093019283020180546001600160c01b0319168155600181018290556002015590556131f1565b600101613029565b505060010161301b565b507f17f582422cfcc57818c51be740311f8ee88583876caf220373ad31cac097bc528383604051612340929190615828565b60975460405163d09a20c560e01b81526001600160a01b039091169063d09a20c59061325d9033906004016157a0565b600060405180830381600087803b15801561327757600080fd5b505af115801561328b573d6000803e3d6000fd5b505050609a829055506040518181527f29bbb39c738a5da8394774006ed1b0ff5a7b1051f5c1e7b4142b5f36950418ed90602001611f1b565b609d81815481106132d457600080fd5b60009182526020909120600390910201805460018201546002909201546001600160a01b0382169350600160a01b820460ff1692600160a81b90920462ffffff16919085565b60355460000361332657565b609d5460008167ffffffffffffffff8111156133445761334461589c565b60405190808252806020026020018201604052801561336d578160200160208202803683370190505b50905060005b8281101561342d57609d818154811061338e5761338e6157c2565b60009182526020909120600390910201546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa1580156133e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134089190615736565b82828151811061341a5761341a6157c2565b6020908102919091010152600101613373565b507376ba3ec5f5adbf1c58c91e86502232317eea72de637fd7d06261345061138c565b6040518263ffffffff1660e01b815260040161346c9190615376565b600060405180830381600087803b15801561348657600080fd5b505af115801561349a573d6000803e3d6000fd5b5050505060005b82811015613591576000609d82815481106134be576134be6157c2565b9060005260206000209060030201905060008383815181106134e2576134e26157c2565b602090810291909101015182546040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015613534573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135589190615736565b613562919061574f565b90508015613587576002820180548201905561357e82826141d9565b61358782614227565b50506001016134a1565b5061359a614565565b6135a2612432565b611fec613ba8565b6000806135b660355490565b905080156135d7576135d26135c9610dec565b85908386614884565b612975565b83612975565b6001600160a01b03831661363f5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161228e565b6001600160a01b0382166136a05760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161228e565b6001600160a01b0383811660008181526034602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60008061370d60355490565b905083158061371a575080155b6135d7576135d28161372a610dec565b86919086614884565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e90604401602060405180830381865afa158015613784573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137a89190615736565b6137b2919061571e565b6040516001600160a01b03851660248201526044810182905290915061381890859063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526148df565b50505050565b600081831061382d57816119a3565b5090919050565b60006138408484612e8b565b90506000198114613818578181101561389b5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161228e565b61381884848484036135dd565b6001600160a01b03831661390c5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b606482015260840161228e565b6001600160a01b03821661396e5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b606482015260840161228e565b6001600160a01b038316600090815260336020526040902054818110156139e65760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b606482015260840161228e565b6001600160a01b0380851660008181526033602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90613a469086815260200190565b60405180910390a3613818565b60006119a383836149b1565b60006119a38383614a00565b6040516001600160a01b038316602482015260448101829052611b6990849063a9059cbb60e01b906064016137e1565b6000610f9c825490565b60006119a38383614af3565b600080613abc610dec565b1180610ef85750506035541590565b609e546000908103613adb575090565b609e54600090620f424090613af0908561593a565b613afa9190615902565b609954909150613b2b907332df62dc3aed2cd6224193052ce665dc181658419033906001600160a01b031684614047565b6119a3818461574f565b6000613b4082611e88565b831115613b8f5760405162461bcd60e51b815260206004820152601e60248201527f455243343632363a206465706f736974206d6f7265207468616e206d61780000604482015260640161228e565b6000613b9a84612e3c565b90506119a333848684614b1d565b6040516370a0823160e01b81523060048201526000907332df62dc3aed2cd6224193052ce665dc18165841906370a0823190602401602060405180830381865afa158015613bfa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c1e9190615736565b905060a3548111156120b6576120b660a35482613c3b919061574f565b61407f565b609e546000908103613c50575090565b6000620f4240609e60000154613c65856128fc565b613c6f919061593a565b613c799190615902565b90506000613c868261137f565b609954909150613cb7907332df62dc3aed2cd6224193052ce665dc181658419033906001600160a01b031685614047565b612975818561574f565b600080613ccd846128fc565b90506119a333848387614b1d565b609f546000908103613cee575081610f9c565b6000620f4240609e60010154613d038661137f565b613d0d919061593a565b613d179190615902565b90506000613d24826128fc565b9050336001600160a01b03851614613d4157613d41843384613834565b609954613d599085906001600160a01b0316846138a8565b613d63818661574f565b95945050505050565b6001600160a01b038416613d935760405163538ba4f960e01b815260040160405180910390fd5b6001600160a01b038516600090815260a5602052604090206005613db682613a9b565b10613dd457604051634d42eda560e01b815260040160405180910390fd5b836001600160a01b0316866001600160a01b031614613df857613df8848784613834565b613e028483614b9b565b8260a36000828254613e14919061571e565b909155505060a18054604080516080810182526001600160a01b03808b168252602082018881528a821693830193845263ffffffff428116606085019081526001870188556000979097529251600386027faadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f649878810180549285166001600160a01b03199093169290921790915590517faadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f64987982015592517faadc37b8ba5645e62f4546802db221593a94729ccbfc5a97d01365a88f64987a909301805495518316600160a01b026001600160c01b0319909616939091169290921793909317905590613f219083908390613a5316565b5060408051828152602081018690529081018490526001600160a01b0380871691888216918a16907f29ee677b5632db3d11fb8c8d0ff321bb6a3c2d20af84dcbae26c1751189e17299060600160405180910390a450505050505050565b609f546000908103613f92575081610f9c565b609f54600090620f424090613fa7908661593a565b613fb19190615902565b9050336001600160a01b03841614613fce57613fce833383613834565b609954613cb79084906001600160a01b0316836138a8565b600054610100900460ff1661400d5760405162461bcd60e51b815260040161228e90615959565b611fec8282614ccf565b600054610100900460ff1661403e5760405162461bcd60e51b815260040161228e90615959565b6120b681614d0f565b6040516001600160a01b03808516602483015283166044820152606481018290526138189085906323b872dd60e01b906084016137e1565b7376ba3ec5f5adbf1c58c91e86502232317eea72de6001600160a01b031663b36b9ffd6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156140d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140f591906158b2565b6001600160a01b031663d9cdd5136040518163ffffffff1660e01b8152600401602060405180830381865afa158015614132573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141569190615736565b8110156141605750565b609b54604051631ba724c760e21b81526004810183905230602482015260448101919091527376ba3ec5f5adbf1c58c91e86502232317eea72de90636e9c931c90606401600060405180830381600087803b1580156141be57600080fd5b505af11580156141d2573d6000803e3d6000fd5b5050505050565b60a054600090620f4240906141ee908461593a565b6141f89190615902565b90508015611b695760028301805482900390556099548354611b69916001600160a01b03918216911683613a6b565b80600101548160020154101561423a5750565b80546000908190600160a01b900460ff16156143d45760028301548354614282916001600160a01b039091169073f4b1486dd74d07706052a33d31d7c0aafd0659e190613733565b8254604080516358b50cef60e11b815290516001600160a01b039092169163b16a19de916004808201926020929091908290030181865afa1580156142cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142ef91906158b2565b60028401546040516001600160a01b03831660248201526044810191909152306064820152909250600090819073f4b1486dd74d07706052a33d31d7c0aafd0659e19060840160408051601f198184030181529181526020820180516001600160e01b0316631a4ca37b60e21b1790525161436a91906159a4565b6000604051808303816000865af19150503d80600081146143a7576040519150601f19603f3d011682016040523d82523d6000602084013e6143ac565b606091505b509150915081156141d257808060200190518101906143cb9190615736565b925050506143ea565b5050805460028201546001600160a01b03909116905b600060028401557382af49447d8a07e3bd95bd0d56f35241523fbab0196001600160a01b0383160161441b57505050565b6144436001600160a01b03831673e592427a0aece92de3edee1f18e0157c0586156483613733565b60408051610100810182526001600160a01b0384811682527382af49447d8a07e3bd95bd0d56f35241523fbab1602083019081528654600160a81b900462ffffff9081168486019081523060608601908152426080870190815260a08701898152600060c0890181815260e08a01918252995163414bf38960e01b815289518916600482015296518816602488015293519094166044860152905185166064850152516084840152905160a4830152935160c482015292511660e48301529073e592427a0aece92de3edee1f18e0157c058615649063414bf38990610104016020604051808303816000875af1158015614541573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141d29190615736565b6040516370a0823160e01b81523060048201526000907382af49447d8a07e3bd95bd0d56f35241523fbab1906370a0823190602401602060405180830381865afa1580156145b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145db9190615736565b9050662386f26fc100008110156145ef5750565b60405163095ea7b360e01b815273ba12222222228d8ba445958a75a0704d566bf2c86004820152602481018290527382af49447d8a07e3bd95bd0d56f35241523fbab19063095ea7b3906044016020604051808303816000875af115801561465b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061467f91906158cf565b50604080516002808252606082018352600092602083019080368337019050509050733082cc23568ea640225c2467653db90e9250aaa0816000815181106146c9576146c96157c2565b60200260200101906001600160a01b031690816001600160a01b0316815250507382af49447d8a07e3bd95bd0d56f35241523fbab181600181518110614711576147116157c2565b6001600160a01b03929092166020928302919091018201526040805160028082526060820183526000939192909183019080368337019050509050600081600081518110614761576147616157c2565b6020026020010181815250508281600181518110614781576147816157c2565b6020026020010181815250506147ba60405180608001604052806060815260200160608152602001606081526020016000151581525090565b82815260208082018390526040516147da916001918591600091016159c0565b60408051601f19818403018152918152828101919091525163172b958560e31b815273ba12222222228d8ba445958a75a0704d566bf2c89063b95cac289061484c907f32df62dc3aed2cd6224193052ce665dc181658410002000000000000000003bd903090819087906004016159ef565b600060405180830381600087803b15801561486657600080fd5b505af115801561487a573d6000803e3d6000fd5b5050505050505050565b600080614892868686614d94565b905060018360028111156148a8576148a8615aae565b1480156148c55750600084806148c0576148c06158ec565b868809115b15613d63576148d560018261571e565b9695505050505050565b6000614934826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614e439092919063ffffffff16565b805190915015611b69578080602001905181019061495291906158cf565b611b695760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161228e565b60008181526001830160205260408120546149f857508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610f9c565b506000610f9c565b60008181526001830160205260408120548015614ae9576000614a2460018361574f565b8554909150600090614a389060019061574f565b9050818114614a9d576000866000018281548110614a5857614a586157c2565b9060005260206000200154905080876000018481548110614a7b57614a7b6157c2565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080614aae57614aae615924565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610f9c565b6000915050610f9c565b6000826000018281548110614b0a57614b0a6157c2565b9060005260206000200154905092915050565b606554614b35906001600160a01b0316853085614047565b614b3f8382614e52565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d78484604051614b8d929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b038216614bfb5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b606482015260840161228e565b6001600160a01b03821660009081526033602052604090205481811015614c6f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b606482015260840161228e565b6001600160a01b03831660008181526033602090815260408083208686039055603580548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b600054610100900460ff16614cf65760405162461bcd60e51b815260040161228e90615959565b6036614d028382615b12565b506037611b698282615b12565b600054610100900460ff16614d365760405162461bcd60e51b815260040161228e90615959565b600080614d4283614f13565b9150915081614d52576012614d54565b805b606580546001600160a01b039095166001600160a01b031960ff93909316600160a01b02929092166001600160a81b031990951694909417179092555050565b6000808060001985870985870292508281108382030391505080600003614dce57838281614dc457614dc46158ec565b04925050506119a3565b808411614dda57600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60606129758484600085614fef565b6001600160a01b038216614ea85760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640161228e565b8060356000828254614eba919061571e565b90915550506001600160a01b0382166000818152603360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b60408051600481526024810182526020810180516001600160e01b031663313ce56760e01b17905290516000918291829182916001600160a01b03871691614f5a916159a4565b600060405180830381855afa9150503d8060008114614f95576040519150601f19603f3d011682016040523d82523d6000602084013e614f9a565b606091505b5091509150818015614fae57506020815110155b15614fe257600081806020019051810190614fc99190615736565b905060ff8111614fe0576001969095509350505050565b505b5060009485945092505050565b6060824710156150505760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161228e565b600080866001600160a01b0316858760405161506c91906159a4565b60006040518083038185875af1925050503d80600081146150a9576040519150601f19603f3d011682016040523d82523d6000602084013e6150ae565b606091505b50915091506150bf878383876150ca565b979650505050505050565b60608315615139578251600003615132576001600160a01b0385163b6151325760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161228e565b5081612975565b612975838381511561514e5781518083602001fd5b8060405162461bcd60e51b815260040161228e91906151c0565b60005b8381101561518357818101518382015260200161516b565b838111156138185750506000910152565b600081518084526151ac816020860160208601615168565b601f01601f19169290920160200192915050565b6020815260006119a36020830184615194565b6000602082840312156151e557600080fd5b5035919050565b60008083601f8401126151fe57600080fd5b50813567ffffffffffffffff81111561521657600080fd5b6020830191508360208260051b850101111561523157600080fd5b9250929050565b6000806000806000806000806080898b03121561525457600080fd5b883567ffffffffffffffff8082111561526c57600080fd5b6152788c838d016151ec565b909a50985060208b013591508082111561529157600080fd5b61529d8c838d016151ec565b909850965060408b01359150808211156152b657600080fd5b6152c28c838d016151ec565b909650945060608b01359150808211156152db57600080fd5b506152e88b828c016151ec565b999c989b5096995094979396929594505050565b6001600160a01b03811681146120b657600080fd5b6000806040838503121561532457600080fd5b823561532f816152fc565b9150602083013561533f816152fc565b809150509250929050565b6000806040838503121561535d57600080fd5b8235615368816152fc565b946020939093013593505050565b6020808252825182820181905260009190848201906040850190845b818110156153b75783516001600160a01b031683529284019291840191600101615392565b50909695505050505050565b60008060008060008060a087890312156153dc57600080fd5b86356153e7816152fc565b955060208701359450604087013593506060870135615405816152fc565b9250608087013567ffffffffffffffff8082111561542257600080fd5b818901915089601f83011261543657600080fd5b81358181111561544557600080fd5b8a602082850101111561545757600080fd5b6020830194508093505050509295509295509295565b60008060006060848603121561548257600080fd5b833561548d816152fc565b9250602084013561549d816152fc565b929592945050506040919091013590565b6000602082840312156154c057600080fd5b81356119a3816152fc565b600081518084526020808501945080840160005b838110156154fb578151875295820195908201906001016154df565b509495945050505050565b60006040808352615519818401866154cb565b83810360208581019190915285518083528682019282019060005b8181101561558057845180516001600160a01b039081168552858201518686015287820151168785015260609081015163ffffffff169084015293830193608090920191600101615534565b509098975050505050505050565b602080825282518282018190526000919060409081850190868401855b828110156155e457815180516001600160d81b03191685528601516001600160e01b0319168685015292840192908501906001016155ab565b5091979650505050505050565b60008060006060848603121561560657600080fd5b505081359360208301359350604090920135919050565b6000806040838503121561563057600080fd5b82359150602083013561533f816152fc565b6020808252825182820181905260009190848201906040850190845b818110156153b75783516001600160d81b0319168352928401929184019160010161565e565b60008060006060848603121561569957600080fd5b8335925060208401356156ab816152fc565b915060408401356156bb816152fc565b809150509250925092565b600080602083850312156156d957600080fd5b823567ffffffffffffffff8111156156f057600080fd5b6156fc858286016151ec565b90969095509350505050565b634e487b7160e01b600052601160045260246000fd5b6000821982111561573157615731615708565b500190565b60006020828403121561574857600080fd5b5051919050565b60008282101561576157615761615708565b500390565b600181811c9082168061577a57607f821691505b60208210810361579a57634e487b7160e01b600052602260045260246000fd5b50919050565b6430b236b4b760d91b81526001600160a01b0391909116602082015260400190565b634e487b7160e01b600052603260045260246000fd5b80151581146120b657600080fd5b6000602082840312156157f857600080fd5b81356119a3816157d8565b60006020828403121561581557600080fd5b813562ffffff811681146119a357600080fd5b60208082528181018390526000908460408401835b8681101561586b578235615850816152fc565b6001600160a01b03168252918301919083019060010161583d565b509695505050505050565b683632bb32b930b3b2b960b91b81526001600160a01b0391909116602082015260400190565b634e487b7160e01b600052604160045260246000fd5b6000602082840312156158c457600080fd5b81516119a3816152fc565b6000602082840312156158e157600080fd5b81516119a3816157d8565b634e487b7160e01b600052601260045260246000fd5b60008261591f57634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603160045260246000fd5b600081600019048311821515161561595457615954615708565b500290565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b600082516159b6818460208701615168565b9190910192915050565b60ff841681526060602082015260006159dc60608301856154cb565b905060ff83166040830152949350505050565b8481526000602060018060a01b038087168285015280861660408501526080606085015261010084018551608080870152818151808452610120880191508583019350600092505b80831015615a5957835185168252928501926001929092019190850190615a37565b50848801519450607f199350838782030160a0880152615a7981866154cb565b94505050506040850151818584030160c0860152615a978382615194565b92505050606084015161586b60e085018215159052565b634e487b7160e01b600052602160045260246000fd5b601f821115611b6957600081815260208120601f850160051c81016020861015615aeb5750805b601f850160051c820191505b81811015615b0a57828155600101615af7565b505050505050565b815167ffffffffffffffff811115615b2c57615b2c61589c565b615b4081615b3a8454615766565b84615ac4565b602080601f831160018114615b755760008415615b5d5750858301515b600019600386901b1c1916600185901b178555615b0a565b600085815260208120601f198616915b82811015615ba457888601518255948401946001909101908401615b85565b5085821015615bc25787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea26469706673582212200b920128d6a77dc7a3ad6ad48074d2b799982932154fae1101630b1d80278c6164736f6c634300080f0033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.