Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
BalancerClaimer
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 10000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// 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.8.0;
import '@mimic-fi/v3-tasks/contracts/Task.sol';
import '@mimic-fi/v3-helpers/contracts/utils/ERC20Helpers.sol';
import './interfaces/IBalancerClaimer.sol';
import './interfaces/IProtocolFeeWithdrawer.sol';
/**
* @title Balancer claimer
* @dev Task used to claim tokens from Balancer's protocol fee withdrawer
*/
contract BalancerClaimer is IBalancerClaimer, Task {
// Execution type for relayers
bytes32 public constant override EXECUTION_TYPE = keccak256('BALANCER_CLAIMER');
// Protocol fee withdrawer address
address public override protocolFeeWithdrawer;
// Protocol fees collector address
address public override protocolFeesCollector;
/**
* @dev Initializes the balancer claimer
* @param config Task config
* @param withdrawer Protocol fee withdrawer address
*/
function initializeBalancerClaimer(TaskConfig memory config, address withdrawer, address collector)
external
virtual
initializer
{
__BalancerClaimer_init(config, withdrawer, collector);
}
/**
* @dev Initializes the balancer claimer. It does call upper contracts initializers.
* @param config Task config
* @param withdrawer Protocol fee withdrawer address
*/
function __BalancerClaimer_init(TaskConfig memory config, address withdrawer, address collector)
internal
onlyInitializing
{
__Task_init(config);
__BalancerClaimer_init_unchained(config, withdrawer, collector);
}
/**
* @dev Initializes the balancer claimer. It does not call upper contracts initializers.
* @param withdrawer Protocol fee withdrawer address
*/
function __BalancerClaimer_init_unchained(TaskConfig memory, address withdrawer, address collector)
internal
onlyInitializing
{
_setProtocolFeeWithdrawer(withdrawer);
_setProtocolFeesCollector(collector);
}
/**
* @dev Tells the address from where the token amounts to execute this task are fetched
*/
function getTokensSource() external view virtual override(IBaseTask, BaseTask) returns (address) {
return protocolFeesCollector;
}
/**
* @dev Tells the token balance in the protocol fees collector available for the smart vault
* @param token Address of the token being queried
*/
function getTaskAmount(address token) public view virtual override(IBaseTask, BaseTask) returns (uint256) {
return ERC20Helpers.balanceOf(token, protocolFeesCollector);
}
/**
* @dev Sets the protocol fee withdrawer address. Sender must be authorized.
* @param newProtocolFeeWithdrawer Address of the protocol fee withdrawer to be set
*/
function setProtocolFeeWithdrawer(address newProtocolFeeWithdrawer)
external
override
authP(authParams(newProtocolFeeWithdrawer))
{
_setProtocolFeeWithdrawer(newProtocolFeeWithdrawer);
}
/**
* @dev Sets the protocol fees collector address. Sender must be authorized.
* @param newProtocolFeesCollector Address of the protocol fees collector to be set
*/
function setProtocolFeesCollector(address newProtocolFeesCollector)
external
override
authP(authParams(newProtocolFeesCollector))
{
_setProtocolFeesCollector(newProtocolFeesCollector);
}
/**
* @dev Executes the Balancer claimer task
*/
function call(address token, uint256 amount) external override authP(authParams(token, amount)) {
if (amount == 0) amount = getTaskAmount(token);
_beforeBalancerClaimer(token, amount);
// solhint-disable-next-line avoid-low-level-calls
ISmartVault(smartVault).call(protocolFeeWithdrawer, _buildBalancerClaimerData(token, amount), 0);
_afterBalancerClaimer(token, amount);
}
/**
* @dev Builds protocol fee withdrawer calldata
*/
function _buildBalancerClaimerData(address token, uint256 amount) internal view returns (bytes memory) {
address[] memory tokens = new address[](1);
tokens[0] = token;
uint256[] memory amounts = new uint256[](1);
amounts[0] = amount;
return
abi.encodeWithSelector(IProtocolFeeWithdrawer.withdrawCollectedFees.selector, tokens, amounts, smartVault);
}
/**
* @dev Before balancer claimer task hook
*/
function _beforeBalancerClaimer(address token, uint256 amount) internal {
_beforeTask(token, amount);
if (token == address(0)) revert TaskTokenZero();
if (amount == 0) revert TaskAmountZero();
}
/**
* @dev After balancer claimer task hook
*/
function _afterBalancerClaimer(address token, uint256 amount) internal {
_increaseBalanceConnector(token, amount);
_afterTask(token, amount);
}
/**
* @dev Sets the protocol fee withdrawer address
* @param newProtocolFeeWithdrawer Address of the protocol fee withdrawer to be set
*/
function _setProtocolFeeWithdrawer(address newProtocolFeeWithdrawer) internal {
if (newProtocolFeeWithdrawer == address(0)) revert TaskProtocolFeeWithdrawerZero();
protocolFeeWithdrawer = newProtocolFeeWithdrawer;
emit ProtocolFeeWithdrawerSet(newProtocolFeeWithdrawer);
}
/**
* @dev Sets the protocol fees collector address
* @param newProtocolFeesCollector Address of the protocol fees collector to be set
*/
function _setProtocolFeesCollector(address newProtocolFeesCollector) internal {
if (newProtocolFeesCollector == address(0)) revert TaskProtocolFeesCollectorZero();
protocolFeesCollector = newProtocolFeesCollector;
emit ProtocolFeesCollectorSet(newProtocolFeesCollector);
}
/**
* @dev Sets the balance connectors. Previous balance connector must be unset.
* @param previous Balance connector id of the previous task in the workflow
* @param next Balance connector id of the next task in the workflow
*/
function _setBalanceConnectors(bytes32 previous, bytes32 next) internal virtual override {
if (previous != bytes32(0)) revert TaskPreviousConnectorNotZero(previous);
super._setBalanceConnectors(previous, next);
}
}// 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.8.17;
import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
import './AuthorizedHelpers.sol';
import './interfaces/IAuthorized.sol';
import './interfaces/IAuthorizer.sol';
/**
* @title Authorized
* @dev Implementation using an authorizer as its access-control mechanism. It offers `auth` and `authP` modifiers to
* tag its own functions in order to control who can access them against the authorizer referenced.
*/
contract Authorized is IAuthorized, Initializable, AuthorizedHelpers {
// Authorizer reference
address public override authorizer;
/**
* @dev Modifier that should be used to tag protected functions
*/
modifier auth() {
_authenticate(msg.sender, msg.sig);
_;
}
/**
* @dev Modifier that should be used to tag protected functions with params
*/
modifier authP(uint256[] memory params) {
_authenticate(msg.sender, msg.sig, params);
_;
}
/**
* @dev Creates a new authorized contract. Note that initializers are disabled at creation time.
*/
constructor() {
_disableInitializers();
}
/**
* @dev Initializes the authorized contract. It does call upper contracts initializers.
* @param _authorizer Address of the authorizer to be set
*/
function __Authorized_init(address _authorizer) internal onlyInitializing {
__Authorized_init_unchained(_authorizer);
}
/**
* @dev Initializes the authorized contract. It does not call upper contracts initializers.
* @param _authorizer Address of the authorizer to be set
*/
function __Authorized_init_unchained(address _authorizer) internal onlyInitializing {
authorizer = _authorizer;
}
/**
* @dev Reverts if `who` is not allowed to call `what`
* @param who Address to be authenticated
* @param what Function selector to be authenticated
*/
function _authenticate(address who, bytes4 what) internal view {
_authenticate(who, what, new uint256[](0));
}
/**
* @dev Reverts if `who` is not allowed to call `what` with `how`
* @param who Address to be authenticated
* @param what Function selector to be authenticated
* @param how Params to be authenticated
*/
function _authenticate(address who, bytes4 what, uint256[] memory how) internal view {
if (!_isAuthorized(who, what, how)) revert AuthSenderNotAllowed(who, what, how);
}
/**
* @dev Tells whether `who` has any permission on this contract
* @param who Address asking permissions for
*/
function _hasPermissions(address who) internal view returns (bool) {
return IAuthorizer(authorizer).hasPermissions(who, address(this));
}
/**
* @dev Tells whether `who` is allowed to call `what`
* @param who Address asking permission for
* @param what Function selector asking permission for
*/
function _isAuthorized(address who, bytes4 what) internal view returns (bool) {
return _isAuthorized(who, what, new uint256[](0));
}
/**
* @dev Tells whether `who` is allowed to call `what` with `how`
* @param who Address asking permission for
* @param what Function selector asking permission for
* @param how Params asking permission for
*/
function _isAuthorized(address who, bytes4 what, uint256[] memory how) internal view returns (bool) {
return IAuthorizer(authorizer).isAuthorized(who, address(this), what, how);
}
}// 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.8.17;
/**
* @title AuthorizedHelpers
* @dev Syntax sugar methods to operate with authorizer params easily
*/
contract AuthorizedHelpers {
function authParams(address p1) internal pure returns (uint256[] memory r) {
return authParams(uint256(uint160(p1)));
}
function authParams(bytes32 p1) internal pure returns (uint256[] memory r) {
return authParams(uint256(p1));
}
function authParams(uint256 p1) internal pure returns (uint256[] memory r) {
r = new uint256[](1);
r[0] = p1;
}
function authParams(address p1, bool p2) internal pure returns (uint256[] memory r) {
r = new uint256[](2);
r[0] = uint256(uint160(p1));
r[1] = p2 ? 1 : 0;
}
function authParams(address p1, uint256 p2) internal pure returns (uint256[] memory r) {
r = new uint256[](2);
r[0] = uint256(uint160(p1));
r[1] = p2;
}
function authParams(address p1, address p2) internal pure returns (uint256[] memory r) {
r = new uint256[](2);
r[0] = uint256(uint160(p1));
r[1] = uint256(uint160(p2));
}
function authParams(bytes32 p1, bytes32 p2) internal pure returns (uint256[] memory r) {
r = new uint256[](2);
r[0] = uint256(p1);
r[1] = uint256(p2);
}
function authParams(address p1, address p2, uint256 p3) internal pure returns (uint256[] memory r) {
r = new uint256[](3);
r[0] = uint256(uint160(p1));
r[1] = uint256(uint160(p2));
r[2] = p3;
}
function authParams(address p1, address p2, address p3) internal pure returns (uint256[] memory r) {
r = new uint256[](3);
r[0] = uint256(uint160(p1));
r[1] = uint256(uint160(p2));
r[2] = uint256(uint160(p3));
}
function authParams(address p1, address p2, bytes4 p3) internal pure returns (uint256[] memory r) {
r = new uint256[](3);
r[0] = uint256(uint160(p1));
r[1] = uint256(uint160(p2));
r[2] = uint256(uint32(p3));
}
function authParams(address p1, uint256 p2, uint256 p3) internal pure returns (uint256[] memory r) {
r = new uint256[](3);
r[0] = uint256(uint160(p1));
r[1] = p2;
r[2] = p3;
}
function authParams(uint256 p1, uint256 p2, uint256 p3, uint256 p4) internal pure returns (uint256[] memory r) {
r = new uint256[](4);
r[0] = p1;
r[1] = p2;
r[2] = p3;
r[3] = p4;
}
function authParams(address p1, address p2, uint256 p3, uint256 p4) internal pure returns (uint256[] memory r) {
r = new uint256[](4);
r[0] = uint256(uint160(p1));
r[1] = uint256(uint160(p2));
r[2] = p3;
r[3] = p4;
}
function authParams(address p1, uint256 p2, uint256 p3, uint256 p4) internal pure returns (uint256[] memory r) {
r = new uint256[](4);
r[0] = uint256(uint160(p1));
r[1] = p2;
r[2] = p3;
r[3] = p4;
}
function authParams(bytes32 p1, address p2, uint256 p3, bool p4) internal pure returns (uint256[] memory r) {
r = new uint256[](4);
r[0] = uint256(p1);
r[1] = uint256(uint160(p2));
r[2] = p3;
r[3] = p4 ? 1 : 0;
}
function authParams(address p1, uint256 p2, uint256 p3, uint256 p4, uint256 p5)
internal
pure
returns (uint256[] memory r)
{
r = new uint256[](5);
r[0] = uint256(uint160(p1));
r[1] = p2;
r[2] = p3;
r[3] = p4;
r[4] = p5;
}
}// 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.8.0;
/**
* @dev Authorized interface
*/
interface IAuthorized {
/**
* @dev Sender `who` is not allowed to call `what` with `how`
*/
error AuthSenderNotAllowed(address who, bytes4 what, uint256[] how);
/**
* @dev Tells the address of the authorizer reference
*/
function authorizer() external view returns (address);
}// 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.8.0;
/**
* @dev Authorizer interface
*/
interface IAuthorizer {
/**
* @dev Permission change
* @param where Address of the contract to change a permission for
* @param changes List of permission changes to be executed
*/
struct PermissionChange {
address where;
GrantPermission[] grants;
RevokePermission[] revokes;
}
/**
* @dev Grant permission data
* @param who Address to be authorized
* @param what Function selector to be authorized
* @param params List of params to restrict the given permission
*/
struct GrantPermission {
address who;
bytes4 what;
Param[] params;
}
/**
* @dev Revoke permission data
* @param who Address to be unauthorized
* @param what Function selector to be unauthorized
*/
struct RevokePermission {
address who;
bytes4 what;
}
/**
* @dev Params used to validate permissions params against
* @param op ID of the operation to compute in order to validate a permission param
* @param value Comparison value
*/
struct Param {
uint8 op;
uint248 value;
}
/**
* @dev Sender is not authorized to call `what` on `where` with `how`
*/
error AuthorizerSenderNotAllowed(address who, address where, bytes4 what, uint256[] how);
/**
* @dev The operation param is invalid
*/
error AuthorizerInvalidParamOp(uint8 op);
/**
* @dev Emitted every time `who`'s permission to perform `what` on `where` is granted with `params`
*/
event Authorized(address indexed who, address indexed where, bytes4 indexed what, Param[] params);
/**
* @dev Emitted every time `who`'s permission to perform `what` on `where` is revoked
*/
event Unauthorized(address indexed who, address indexed where, bytes4 indexed what);
/**
* @dev Tells whether `who` has any permission on `where`
* @param who Address asking permission for
* @param where Target address asking permission for
*/
function hasPermissions(address who, address where) external view returns (bool);
/**
* @dev Tells the number of permissions `who` has on `where`
* @param who Address asking permission for
* @param where Target address asking permission for
*/
function getPermissionsLength(address who, address where) external view returns (uint256);
/**
* @dev Tells whether `who` has permission to call `what` on `where`. Note `how` is not evaluated here,
* which means `who` might be authorized on or not depending on the call at the moment of the execution
* @param who Address asking permission for
* @param where Target address asking permission for
* @param what Function selector asking permission for
*/
function hasPermission(address who, address where, bytes4 what) external view returns (bool);
/**
* @dev Tells whether `who` is allowed to call `what` on `where` with `how`
* @param who Address asking permission for
* @param where Target address asking permission for
* @param what Function selector asking permission for
* @param how Params asking permission for
*/
function isAuthorized(address who, address where, bytes4 what, uint256[] memory how) external view returns (bool);
/**
* @dev Tells the params set for a given permission
* @param who Address asking permission params of
* @param where Target address asking permission params of
* @param what Function selector asking permission params of
*/
function getPermissionParams(address who, address where, bytes4 what) external view returns (Param[] memory);
/**
* @dev Executes a list of permission changes
* @param changes List of permission changes to be executed
*/
function changePermissions(PermissionChange[] memory changes) external;
/**
* @dev Authorizes `who` to call `what` on `where` restricted by `params`
* @param who Address to be authorized
* @param where Target address to be granted for
* @param what Function selector to be granted
* @param params Optional params to restrict a permission attempt
*/
function authorize(address who, address where, bytes4 what, Param[] memory params) external;
/**
* @dev Unauthorizes `who` to call `what` on `where`. Sender must be authorized.
* @param who Address to be authorized
* @param where Target address to be revoked for
* @param what Function selector to be revoked
*/
function unauthorize(address who, address where, bytes4 what) 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.8.0;
/**
* @title FixedPoint
* @dev Math library to operate with fixed point values with 18 decimals
*/
library FixedPoint {
// 1 in fixed point value: 18 decimal places
uint256 internal constant ONE = 1e18;
/**
* @dev Multiplication overflow
*/
error FixedPointMulOverflow(uint256 a, uint256 b);
/**
* @dev Division by zero
*/
error FixedPointZeroDivision();
/**
* @dev Division internal error
*/
error FixedPointDivInternal(uint256 a, uint256 aInflated);
/**
* @dev Multiplies two fixed point numbers rounding down
*/
function mulDown(uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
uint256 product = a * b;
if (a != 0 && product / a != b) revert FixedPointMulOverflow(a, b);
return product / ONE;
}
}
/**
* @dev Multiplies two fixed point numbers rounding up
*/
function mulUp(uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
uint256 product = a * b;
if (a != 0 && product / a != b) revert FixedPointMulOverflow(a, b);
return product == 0 ? 0 : (((product - 1) / ONE) + 1);
}
}
/**
* @dev Divides two fixed point numbers rounding down
*/
function divDown(uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
if (b == 0) revert FixedPointZeroDivision();
if (a == 0) return 0;
uint256 aInflated = a * ONE;
if (aInflated / a != ONE) revert FixedPointDivInternal(a, aInflated);
return aInflated / b;
}
}
/**
* @dev Divides two fixed point numbers rounding up
*/
function divUp(uint256 a, uint256 b) internal pure returns (uint256) {
unchecked {
if (b == 0) revert FixedPointZeroDivision();
if (a == 0) return 0;
uint256 aInflated = a * ONE;
if (aInflated / a != ONE) revert FixedPointDivInternal(a, aInflated);
return ((aInflated - 1) / b) + 1;
}
}
}// 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.8.0;
/**
* @title Denominations
* @dev Provides a list of ground denominations for those tokens that cannot be represented by an ERC20.
* For now, the only needed is the native token that could be ETH, MATIC, or other depending on the layer being operated.
*/
library Denominations {
address internal constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
// Fiat currencies follow https://en.wikipedia.org/wiki/ISO_4217
address internal constant USD = address(840);
function isNativeToken(address token) internal pure returns (bool) {
return token == NATIVE_TOKEN;
}
}// 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.8.0;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import './Denominations.sol';
/**
* @title ERC20Helpers
* @dev Provides a list of ERC20 helper methods
*/
library ERC20Helpers {
function approve(address token, address to, uint256 amount) internal {
SafeERC20.forceApprove(IERC20(token), to, amount);
}
function transfer(address token, address to, uint256 amount) internal {
if (Denominations.isNativeToken(token)) Address.sendValue(payable(to), amount);
else SafeERC20.safeTransfer(IERC20(token), to, amount);
}
function balanceOf(address token, address account) internal view returns (uint256) {
if (Denominations.isNativeToken(token)) return address(account).balance;
else return IERC20(token).balanceOf(address(account));
}
}// 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.8.0;
import '@mimic-fi/v3-authorizer/contracts/interfaces/IAuthorized.sol';
/**
* @title IPriceOracle
* @dev Price oracle interface
*
* Tells the price of a token (base) in a given quote based the following rule: the response is expressed using the
* corresponding number of decimals so that when performing a fixed point product of it by a `base` amount it results
* in a value expressed in `quote` decimals. For example, if `base` is ETH and `quote` is USDC, then the returned
* value is expected to be expressed using 6 decimals:
*
* FixedPoint.mul(X[ETH], price[USDC/ETH]) = FixedPoint.mul(X[18], price[6]) = X * price [6]
*/
interface IPriceOracle is IAuthorized {
/**
* @dev Price data
* @param base Token to rate
* @param quote Token used for the price rate
* @param rate Price of a token (base) expressed in `quote`
* @param deadline Expiration timestamp until when the given quote is considered valid
*/
struct PriceData {
address base;
address quote;
uint256 rate;
uint256 deadline;
}
/**
* @dev The signer is not allowed
*/
error PriceOracleInvalidSigner(address signer);
/**
* @dev The feed for the given (base, quote) pair doesn't exist
*/
error PriceOracleMissingFeed(address base, address quote);
/**
* @dev The price deadline is in the past
*/
error PriceOracleOutdatedPrice(address base, address quote, uint256 deadline, uint256 currentTimestamp);
/**
* @dev The base decimals are bigger than the quote decimals plus the fixed point decimals
*/
error PriceOracleBaseDecimalsTooBig(address base, uint256 baseDecimals, address quote, uint256 quoteDecimals);
/**
* @dev The inverse feed decimals are bigger than the maximum inverse feed decimals
*/
error PriceOracleInverseFeedDecimalsTooBig(address inverseFeed, uint256 inverseFeedDecimals);
/**
* @dev The quote feed decimals are bigger than the base feed decimals plus the fixed point decimals
*/
error PriceOracleQuoteFeedDecimalsTooBig(uint256 quoteFeedDecimals, uint256 baseFeedDecimals);
/**
* @dev Emitted every time a signer is changed
*/
event SignerSet(address indexed signer, bool allowed);
/**
* @dev Emitted every time a feed is set for (base, quote) pair
*/
event FeedSet(address indexed base, address indexed quote, address feed);
/**
* @dev Tells whether an address is as an allowed signer or not
* @param signer Address of the signer being queried
*/
function isSignerAllowed(address signer) external view returns (bool);
/**
* @dev Tells the list of allowed signers
*/
function getAllowedSigners() external view returns (address[] memory);
/**
* @dev Tells the digest expected to be signed by the off-chain oracle signers for a list of prices
* @param prices List of prices to be signed
*/
function getPricesDigest(PriceData[] memory prices) external view returns (bytes32);
/**
* @dev Tells the price of a token `base` expressed in a token `quote`
* @param base Token to rate
* @param quote Token used for the price rate
*/
function getPrice(address base, address quote) external view returns (uint256);
/**
* @dev Tells the price of a token `base` expressed in a token `quote`
* @param base Token to rate
* @param quote Token used for the price rate
* @param data Encoded data to validate in order to compute the requested rate
*/
function getPrice(address base, address quote, bytes memory data) external view returns (uint256);
/**
* @dev Tells the feed address for (base, quote) pair. It returns the zero address if there is no one set.
* @param base Token to be rated
* @param quote Token used for the price rate
*/
function getFeed(address base, address quote) external view returns (address);
/**
* @dev Sets a signer condition
* @param signer Address of the signer to be set
* @param allowed Whether the requested signer is allowed
*/
function setSigner(address signer, bool allowed) external;
/**
* @dev Sets a feed for a (base, quote) pair
* @param base Token base to be set
* @param quote Token quote to be set
* @param feed Feed to be set
*/
function setFeed(address base, address quote, address feed) 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.8.0;
import '@mimic-fi/v3-authorizer/contracts/interfaces/IAuthorized.sol';
/**
* @dev Smart Vault interface
*/
interface ISmartVault is IAuthorized {
/**
* @dev The smart vault is paused
*/
error SmartVaultPaused();
/**
* @dev The smart vault is unpaused
*/
error SmartVaultUnpaused();
/**
* @dev The token is zero
*/
error SmartVaultTokenZero();
/**
* @dev The amount is zero
*/
error SmartVaultAmountZero();
/**
* @dev The recipient is zero
*/
error SmartVaultRecipientZero();
/**
* @dev The connector is deprecated
*/
error SmartVaultConnectorDeprecated(address connector);
/**
* @dev The connector is not registered
*/
error SmartVaultConnectorNotRegistered(address connector);
/**
* @dev The connector is not stateless
*/
error SmartVaultConnectorNotStateless(address connector);
/**
* @dev The connector ID is zero
*/
error SmartVaultBalanceConnectorIdZero();
/**
* @dev The balance connector's balance is lower than the requested amount to be deducted
*/
error SmartVaultBalanceConnectorInsufficientBalance(bytes32 id, address token, uint256 balance, uint256 amount);
/**
* @dev The smart vault's native token balance is lower than the requested amount to be deducted
*/
error SmartVaultInsufficientNativeTokenBalance(uint256 balance, uint256 amount);
/**
* @dev Emitted every time a smart vault is paused
*/
event Paused();
/**
* @dev Emitted every time a smart vault is unpaused
*/
event Unpaused();
/**
* @dev Emitted every time the price oracle is set
*/
event PriceOracleSet(address indexed priceOracle);
/**
* @dev Emitted every time a connector check is overridden
*/
event ConnectorCheckOverridden(address indexed connector, bool ignored);
/**
* @dev Emitted every time a balance connector is updated
*/
event BalanceConnectorUpdated(bytes32 indexed id, address indexed token, uint256 amount, bool added);
/**
* @dev Emitted every time `execute` is called
*/
event Executed(address indexed connector, bytes data, bytes result);
/**
* @dev Emitted every time `call` is called
*/
event Called(address indexed target, bytes data, uint256 value, bytes result);
/**
* @dev Emitted every time `wrap` is called
*/
event Wrapped(uint256 amount);
/**
* @dev Emitted every time `unwrap` is called
*/
event Unwrapped(uint256 amount);
/**
* @dev Emitted every time `collect` is called
*/
event Collected(address indexed token, address indexed from, uint256 amount);
/**
* @dev Emitted every time `withdraw` is called
*/
event Withdrawn(address indexed token, address indexed recipient, uint256 amount, uint256 fee);
/**
* @dev Tells if the smart vault is paused or not
*/
function isPaused() external view returns (bool);
/**
* @dev Tells the address of the price oracle
*/
function priceOracle() external view returns (address);
/**
* @dev Tells the address of the Mimic's registry
*/
function registry() external view returns (address);
/**
* @dev Tells the address of the Mimic's fee controller
*/
function feeController() external view returns (address);
/**
* @dev Tells the address of the wrapped native token
*/
function wrappedNativeToken() external view returns (address);
/**
* @dev Tells if a connector check is ignored
* @param connector Address of the connector being queried
*/
function isConnectorCheckIgnored(address connector) external view returns (bool);
/**
* @dev Tells the balance to a balance connector for a token
* @param id Balance connector identifier
* @param token Address of the token querying the balance connector for
*/
function getBalanceConnector(bytes32 id, address token) external view returns (uint256);
/**
* @dev Tells whether someone has any permission over the smart vault
*/
function hasPermissions(address who) external view returns (bool);
/**
* @dev Pauses a smart vault
*/
function pause() external;
/**
* @dev Unpauses a smart vault
*/
function unpause() external;
/**
* @dev Sets the price oracle
* @param newPriceOracle Address of the new price oracle to be set
*/
function setPriceOracle(address newPriceOracle) external;
/**
* @dev Overrides connector checks
* @param connector Address of the connector to override its check
* @param ignored Whether the connector check should be ignored
*/
function overrideConnectorCheck(address connector, bool ignored) external;
/**
* @dev Updates a balance connector
* @param id Balance connector identifier to be updated
* @param token Address of the token to update the balance connector for
* @param amount Amount to be updated to the balance connector
* @param add Whether the balance connector should be increased or decreased
*/
function updateBalanceConnector(bytes32 id, address token, uint256 amount, bool add) external;
/**
* @dev Executes a connector inside of the Smart Vault context
* @param connector Address of the connector that will be executed
* @param data Call data to be used for the delegate-call
* @return result Call response if it was successful, otherwise it reverts
*/
function execute(address connector, bytes memory data) external returns (bytes memory result);
/**
* @dev Executes an arbitrary call from the Smart Vault
* @param target Address where the call will be sent
* @param data Call data to be used for the call
* @param value Value in wei that will be attached to the call
* @return result Call response if it was successful, otherwise it reverts
*/
function call(address target, bytes memory data, uint256 value) external returns (bytes memory result);
/**
* @dev Wrap an amount of native tokens to the wrapped ERC20 version of it
* @param amount Amount of native tokens to be wrapped
*/
function wrap(uint256 amount) external;
/**
* @dev Unwrap an amount of wrapped native tokens
* @param amount Amount of wrapped native tokens to unwrapped
*/
function unwrap(uint256 amount) external;
/**
* @dev Collect tokens from an external account to the Smart Vault
* @param token Address of the token to be collected
* @param from Address where the tokens will be transferred from
* @param amount Amount of tokens to be transferred
*/
function collect(address token, address from, uint256 amount) external;
/**
* @dev Withdraw tokens to an external account
* @param token Address of the token to be withdrawn
* @param recipient Address where the tokens will be transferred to
* @param amount Amount of tokens to withdraw
*/
function withdraw(address token, address recipient, uint256 amount) 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.8.0;
import '@mimic-fi/v3-authorizer/contracts/Authorized.sol';
import '@mimic-fi/v3-helpers/contracts/math/FixedPoint.sol';
import '@mimic-fi/v3-helpers/contracts/utils/Denominations.sol';
import '@mimic-fi/v3-price-oracle/contracts/interfaces/IPriceOracle.sol';
import '@mimic-fi/v3-smart-vault/contracts/interfaces/ISmartVault.sol';
import '../interfaces/base/IBaseTask.sol';
/**
* @title BaseTask
* @dev Base task implementation with a Smart Vault reference and using the Authorizer
*/
abstract contract BaseTask is IBaseTask, Authorized {
// Smart Vault reference
address public override smartVault;
// Optional balance connector id for the previous task in the workflow
bytes32 internal previousBalanceConnectorId;
// Optional balance connector id for the next task in the workflow
bytes32 internal nextBalanceConnectorId;
/**
* @dev Base task config. Only used in the initializer.
* @param smartVault Address of the smart vault this task will reference, it cannot be changed once set
* @param previousBalanceConnectorId Balance connector id for the previous task in the workflow
* @param nextBalanceConnectorId Balance connector id for the next task in the workflow
*/
struct BaseConfig {
address smartVault;
bytes32 previousBalanceConnectorId;
bytes32 nextBalanceConnectorId;
}
/**
* @dev Initializes the base task. It does call upper contracts initializers.
* @param config Base task config
*/
function __BaseTask_init(BaseConfig memory config) internal onlyInitializing {
__Authorized_init(ISmartVault(config.smartVault).authorizer());
__BaseTask_init_unchained(config);
}
/**
* @dev Initializes the base task. It does not call upper contracts initializers.
* @param config Base task config
*/
function __BaseTask_init_unchained(BaseConfig memory config) internal onlyInitializing {
smartVault = config.smartVault;
_setBalanceConnectors(config.previousBalanceConnectorId, config.nextBalanceConnectorId);
}
/**
* @dev Tells the address from where the token amounts to execute this task are fetched.
* Since by default tasks are supposed to use balance connectors, the tokens source has to be the smart vault.
* In case a task does not need to rely on a previous balance connector, it must override this function to specify
* where it is getting its tokens from.
*/
function getTokensSource() external view virtual override returns (address) {
return smartVault;
}
/**
* @dev Tells the amount a task should use for a token. By default tasks are expected to use balance connectors.
* In case a task relies on an external tokens source, it must override how the task amount is calculated.
* @param token Address of the token being queried
*/
function getTaskAmount(address token) public view virtual override returns (uint256) {
return ISmartVault(smartVault).getBalanceConnector(previousBalanceConnectorId, token);
}
/**
* @dev Tells the previous and next balance connectors id of the previous task in the workflow
*/
function getBalanceConnectors() external view returns (bytes32 previous, bytes32 next) {
previous = previousBalanceConnectorId;
next = nextBalanceConnectorId;
}
/**
* @dev Sets the balance connectors
* @param previous Balance connector id of the previous task in the workflow
* @param next Balance connector id of the next task in the workflow
*/
function setBalanceConnectors(bytes32 previous, bytes32 next) external override authP(authParams(previous, next)) {
_setBalanceConnectors(previous, next);
}
/**
* @dev Tells the wrapped native token address if the given address is the native token
* @param token Address of the token to be checked
*/
function _wrappedIfNative(address token) internal view returns (address) {
return Denominations.isNativeToken(token) ? _wrappedNativeToken() : token;
}
/**
* @dev Tells whether a token is the native or the wrapped native token
* @param token Address of the token to be checked
*/
function _isWrappedOrNative(address token) internal view returns (bool) {
return Denominations.isNativeToken(token) || token == _wrappedNativeToken();
}
/**
* @dev Tells the wrapped native token address
*/
function _wrappedNativeToken() internal view returns (address) {
return ISmartVault(smartVault).wrappedNativeToken();
}
/**
* @dev Fetches a base/quote price from the smart vault's price oracle
* @param base Token to rate
* @param quote Token used for the price rate
*/
function _getPrice(address base, address quote) internal view virtual returns (uint256) {
address priceOracle = ISmartVault(smartVault).priceOracle();
if (priceOracle == address(0)) revert TaskSmartVaultPriceOracleNotSet(smartVault);
bytes memory extraCallData = _decodeExtraCallData();
return
extraCallData.length == 0
? IPriceOracle(priceOracle).getPrice(_wrappedIfNative(base), _wrappedIfNative(quote))
: IPriceOracle(priceOracle).getPrice(_wrappedIfNative(base), _wrappedIfNative(quote), extraCallData);
}
/**
* @dev Before base task hook
*/
function _beforeBaseTask(address token, uint256 amount) internal virtual {
_decreaseBalanceConnector(token, amount);
}
/**
* @dev After base task hook
*/
function _afterBaseTask(address, uint256) internal virtual {
emit Executed();
}
/**
* @dev Decreases the previous balance connector in the smart vault if defined
* @param token Address of the token to update the previous balance connector of
* @param amount Amount to be updated
*/
function _decreaseBalanceConnector(address token, uint256 amount) internal {
if (previousBalanceConnectorId != bytes32(0)) {
ISmartVault(smartVault).updateBalanceConnector(previousBalanceConnectorId, token, amount, false);
}
}
/**
* @dev Increases the next balance connector in the smart vault if defined
* @param token Address of the token to update the next balance connector of
* @param amount Amount to be updated
*/
function _increaseBalanceConnector(address token, uint256 amount) internal {
if (nextBalanceConnectorId != bytes32(0)) {
ISmartVault(smartVault).updateBalanceConnector(nextBalanceConnectorId, token, amount, true);
}
}
/**
* @dev Sets the balance connectors
* @param previous Balance connector id of the previous task in the workflow
* @param next Balance connector id of the next task in the workflow
*/
function _setBalanceConnectors(bytes32 previous, bytes32 next) internal virtual {
if (previous == next && previous != bytes32(0)) revert TaskSameBalanceConnectors(previous);
previousBalanceConnectorId = previous;
nextBalanceConnectorId = next;
emit BalanceConnectorsSet(previous, next);
}
/**
* @dev Decodes any potential extra calldata stored in the calldata space. Tasks relying on the extra calldata
* pattern, assume that the last word of the calldata stores the extra calldata length so it can be decoded. Note
* that tasks relying on this pattern must contemplate this function may return bogus data if no extra calldata
* was given.
*/
function _decodeExtraCallData() private pure returns (bytes memory data) {
uint256 length = uint256(_decodeLastCallDataWord());
if (msg.data.length < length) return new bytes(0);
data = new bytes(length);
assembly {
calldatacopy(add(data, 0x20), sub(sub(calldatasize(), length), 0x20), length)
}
}
/**
* @dev Returns the last calldata word. This function returns zero if the calldata is not long enough.
*/
function _decodeLastCallDataWord() private pure returns (bytes32 result) {
if (msg.data.length < 36) return bytes32(0);
assembly {
result := calldataload(sub(calldatasize(), 0x20))
}
}
}// 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.8.17;
import '@mimic-fi/v3-authorizer/contracts/Authorized.sol';
import '@mimic-fi/v3-helpers/contracts/math/FixedPoint.sol';
import '@mimic-fi/v3-smart-vault/contracts/interfaces/ISmartVault.sol';
import '../interfaces/base/IGasLimitedTask.sol';
/**
* @dev Gas config for tasks. It allows setting different gas-related configs, specially useful to control relayed txs.
*/
abstract contract GasLimitedTask is IGasLimitedTask, Authorized {
using FixedPoint for uint256;
// Variable used to allow a better developer experience to reimburse tx gas cost
// solhint-disable-next-line var-name-mixedcase
uint256 private __initialGas__;
// Gas limits config
GasLimitConfig internal gasLimits;
/**
* @dev Gas limits config
* @param gasPriceLimit Gas price limit expressed in the native token
* @param priorityFeeLimit Priority fee limit expressed in the native token
* @param txCostLimit Transaction cost limit to be set
* @param txCostLimitPct Transaction cost limit percentage to be set
*/
struct GasLimitConfig {
uint256 gasPriceLimit;
uint256 priorityFeeLimit;
uint256 txCostLimit;
uint256 txCostLimitPct;
}
/**
* @dev Initializes the gas limited task. It does call upper contracts initializers.
* @param config Gas limited task config
*/
function __GasLimitedTask_init(GasLimitConfig memory config) internal onlyInitializing {
__GasLimitedTask_init_unchained(config);
}
/**
* @dev Initializes the gas limited task. It does not call upper contracts initializers.
* @param config Gas limited task config
*/
function __GasLimitedTask_init_unchained(GasLimitConfig memory config) internal onlyInitializing {
_setGasLimits(config.gasPriceLimit, config.priorityFeeLimit, config.txCostLimit, config.txCostLimitPct);
}
/**
* @dev Tells the gas limits config
*/
function getGasLimits()
external
view
returns (uint256 gasPriceLimit, uint256 priorityFeeLimit, uint256 txCostLimit, uint256 txCostLimitPct)
{
return (gasLimits.gasPriceLimit, gasLimits.priorityFeeLimit, gasLimits.txCostLimit, gasLimits.txCostLimitPct);
}
/**
* @dev Sets the gas limits config
* @param newGasPriceLimit New gas price limit to be set
* @param newPriorityFeeLimit New priority fee limit to be set
* @param newTxCostLimit New tx cost limit to be set
* @param newTxCostLimitPct New tx cost percentage limit to be set
*/
function setGasLimits(
uint256 newGasPriceLimit,
uint256 newPriorityFeeLimit,
uint256 newTxCostLimit,
uint256 newTxCostLimitPct
) external override authP(authParams(newGasPriceLimit, newPriorityFeeLimit, newTxCostLimit, newTxCostLimitPct)) {
_setGasLimits(newGasPriceLimit, newPriorityFeeLimit, newTxCostLimit, newTxCostLimitPct);
}
/**
* @dev Fetches a base/quote price
*/
function _getPrice(address base, address quote) internal view virtual returns (uint256);
/**
* @dev Initializes gas limited tasks and validates gas price limit
*/
function _beforeGasLimitedTask(address, uint256) internal virtual {
__initialGas__ = gasleft();
GasLimitConfig memory config = gasLimits;
bool isGasPriceAllowed = config.gasPriceLimit == 0 || tx.gasprice <= config.gasPriceLimit;
if (!isGasPriceAllowed) revert TaskGasPriceLimitExceeded(tx.gasprice, config.gasPriceLimit);
uint256 priorityFee = tx.gasprice - block.basefee;
bool isPriorityFeeAllowed = config.priorityFeeLimit == 0 || priorityFee <= config.priorityFeeLimit;
if (!isPriorityFeeAllowed) revert TaskPriorityFeeLimitExceeded(priorityFee, config.priorityFeeLimit);
}
/**
* @dev Validates transaction cost limit
*/
function _afterGasLimitedTask(address token, uint256 amount) internal virtual {
if (__initialGas__ == 0) revert TaskGasNotInitialized();
GasLimitConfig memory config = gasLimits;
uint256 totalGas = __initialGas__ - gasleft();
uint256 totalCost = totalGas * tx.gasprice;
bool isTxCostAllowed = config.txCostLimit == 0 || totalCost <= config.txCostLimit;
if (!isTxCostAllowed) revert TaskTxCostLimitExceeded(totalCost, config.txCostLimit);
delete __initialGas__;
if (config.txCostLimitPct > 0 && amount > 0) {
uint256 price = _getPrice(ISmartVault(this.smartVault()).wrappedNativeToken(), token);
uint256 totalCostInToken = totalCost.mulUp(price);
uint256 txCostPct = totalCostInToken.divUp(amount);
if (txCostPct > config.txCostLimitPct) revert TaskTxCostLimitPctExceeded(txCostPct, config.txCostLimitPct);
}
}
/**
* @dev Sets the gas limits config
* @param newGasPriceLimit New gas price limit to be set
* @param newPriorityFeeLimit New priority fee limit to be set
* @param newTxCostLimit New tx cost limit to be set
* @param newTxCostLimitPct New tx cost percentage limit to be set
*/
function _setGasLimits(
uint256 newGasPriceLimit,
uint256 newPriorityFeeLimit,
uint256 newTxCostLimit,
uint256 newTxCostLimitPct
) internal {
if (newTxCostLimitPct > FixedPoint.ONE) revert TaskTxCostLimitPctAboveOne();
gasLimits.gasPriceLimit = newGasPriceLimit;
gasLimits.priorityFeeLimit = newPriorityFeeLimit;
gasLimits.txCostLimit = newTxCostLimit;
gasLimits.txCostLimitPct = newTxCostLimitPct;
emit GasLimitsSet(newGasPriceLimit, newPriorityFeeLimit, newTxCostLimit, newTxCostLimitPct);
}
}// 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.8.17;
import '@mimic-fi/v3-authorizer/contracts/Authorized.sol';
import '@mimic-fi/v3-helpers/contracts/math/FixedPoint.sol';
import '../interfaces/base/IPausableTask.sol';
/**
* @dev Pausable config for tasks
*/
abstract contract PausableTask is IPausableTask, Authorized {
using FixedPoint for uint256;
// Whether the task is paused or not
bool public override isPaused;
/**
* @dev Initializes the pausable task. It does call upper contracts initializers.
*/
function __PausableTask_init() internal onlyInitializing {
__PausableTask_init_unchained();
}
/**
* @dev Initializes the pausable task. It does not call upper contracts initializers.
*/
function __PausableTask_init_unchained() internal onlyInitializing {
// solhint-disable-previous-line no-empty-blocks
}
/**
* @dev Pauses a task
*/
function pause() external override auth {
if (isPaused) revert TaskPaused();
isPaused = true;
emit Paused();
}
/**
* @dev Unpauses a task
*/
function unpause() external override auth {
if (!isPaused) revert TaskUnpaused();
isPaused = false;
emit Unpaused();
}
/**
* @dev Before pausable task hook
*/
function _beforePausableTask(address, uint256) internal virtual {
if (isPaused) revert TaskPaused();
}
/**
* @dev After pausable task hook
*/
function _afterPausableTask(address, uint256) internal virtual {
// 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.8.3;
import '@quant-finance/solidity-datetime/contracts/DateTime.sol';
import '@mimic-fi/v3-authorizer/contracts/Authorized.sol';
import '../interfaces/base/ITimeLockedTask.sol';
/**
* @dev Time lock config for tasks. It allows limiting the frequency of a task.
*/
abstract contract TimeLockedTask is ITimeLockedTask, Authorized {
using DateTime for uint256;
uint256 private constant DAYS_28 = 60 * 60 * 24 * 28;
/**
* @dev Time-locks supports different frequency modes
* @param Seconds To indicate the execution must occur every certain number of seconds
* @param OnDay To indicate the execution must occur on day number from 1 to 28 every certain months
* @param OnLastMonthDay To indicate the execution must occur on the last day of the month every certain months
*/
enum Mode {
Seconds,
OnDay,
OnLastMonthDay
}
// Time lock mode
Mode internal _mode;
// Time lock frequency
uint256 internal _frequency;
// Future timestamp since when the task can be executed
uint256 internal _allowedAt;
// Next future timestamp since when the task can be executed to be set, only used internally
uint256 internal _nextAllowedAt;
// Period in seconds during when a time-locked task can be executed since the allowed timestamp
uint256 internal _window;
/**
* @dev Time lock config params. Only used in the initializer.
* @param mode Time lock mode
* @param frequency Time lock frequency value
* @param allowedAt Time lock allowed date
* @param window Time lock execution window
*/
struct TimeLockConfig {
uint8 mode;
uint256 frequency;
uint256 allowedAt;
uint256 window;
}
/**
* @dev Initializes the time locked task. It does not call upper contracts initializers.
* @param config Time locked task config
*/
function __TimeLockedTask_init(TimeLockConfig memory config) internal onlyInitializing {
__TimeLockedTask_init_unchained(config);
}
/**
* @dev Initializes the time locked task. It does call upper contracts initializers.
* @param config Time locked task config
*/
function __TimeLockedTask_init_unchained(TimeLockConfig memory config) internal onlyInitializing {
_setTimeLock(config.mode, config.frequency, config.allowedAt, config.window);
}
/**
* @dev Tells the time-lock related information
*/
function getTimeLock() external view returns (uint8 mode, uint256 frequency, uint256 allowedAt, uint256 window) {
return (uint8(_mode), _frequency, _allowedAt, _window);
}
/**
* @dev Sets a new time lock
*/
function setTimeLock(uint8 mode, uint256 frequency, uint256 allowedAt, uint256 window)
external
override
authP(authParams(mode, frequency, allowedAt, window))
{
_setTimeLock(mode, frequency, allowedAt, window);
}
/**
* @dev Before time locked task hook
*/
function _beforeTimeLockedTask(address, uint256) internal virtual {
// Load storage variables
Mode mode = _mode;
uint256 frequency = _frequency;
uint256 allowedAt = _allowedAt;
uint256 window = _window;
// First we check the current timestamp is not in the past
if (block.timestamp < allowedAt) revert TaskTimeLockActive(block.timestamp, allowedAt);
if (mode == Mode.Seconds) {
if (frequency == 0) return;
// If no window is set, the next allowed date is simply moved the number of seconds set as frequency.
// Otherwise, the offset must be validated and the next allowed date is set to the next period.
if (window == 0) _nextAllowedAt = block.timestamp + frequency;
else {
uint256 diff = block.timestamp - allowedAt;
uint256 periods = diff / frequency;
uint256 offset = diff - (periods * frequency);
if (offset > window) revert TaskTimeLockActive(block.timestamp, allowedAt);
_nextAllowedAt = allowedAt + ((periods + 1) * frequency);
}
} else {
if (block.timestamp >= allowedAt && block.timestamp <= allowedAt + window) {
// Check the current timestamp has not passed the allowed date set
_nextAllowedAt = _getNextAllowedDate(allowedAt, frequency);
} else {
// Check the current timestamp is not before the current allowed date
uint256 currentAllowedDay = mode == Mode.OnDay ? allowedAt.getDay() : block.timestamp.getDaysInMonth();
uint256 currentAllowedAt = _getCurrentAllowedDate(allowedAt, currentAllowedDay);
if (block.timestamp < currentAllowedAt) revert TaskTimeLockActive(block.timestamp, currentAllowedAt);
// Check the current timestamp has not passed the allowed execution window
uint256 extendedCurrentAllowedAt = currentAllowedAt + window;
bool exceedsExecutionWindow = block.timestamp > extendedCurrentAllowedAt;
if (exceedsExecutionWindow) revert TaskTimeLockActive(block.timestamp, extendedCurrentAllowedAt);
// Finally set the next allowed date to the corresponding number of months from the current date
_nextAllowedAt = _getNextAllowedDate(currentAllowedAt, frequency);
}
}
}
/**
* @dev After time locked task hook
*/
function _afterTimeLockedTask(address, uint256) internal virtual {
if (_nextAllowedAt == 0) return;
_setTimeLockAllowedAt(_nextAllowedAt);
_nextAllowedAt = 0;
}
/**
* @dev Sets a new time lock
*/
function _setTimeLock(uint8 mode, uint256 frequency, uint256 allowedAt, uint256 window) internal {
if (mode == uint8(Mode.Seconds)) {
// The execution window and timestamp are optional, but both must be given or none
// If given the execution window cannot be larger than the number of seconds
// Also, if these are given the frequency must be checked as well, otherwise it could be unsetting the lock
if (window > 0 || allowedAt > 0) {
if (frequency == 0) revert TaskInvalidFrequency(mode, frequency);
if (window == 0 || window > frequency) revert TaskInvalidAllowedWindow(mode, window);
if (allowedAt == 0) revert TaskInvalidAllowedDate(mode, allowedAt);
}
} else {
// The other modes can be "on-day" or "on-last-day" where the frequency represents a number of months
// There is no limit for the frequency, it simply cannot be zero
if (frequency == 0) revert TaskInvalidFrequency(mode, frequency);
// The execution window cannot be larger than the number of months considering months of 28 days
if (window == 0 || window > frequency * DAYS_28) revert TaskInvalidAllowedWindow(mode, window);
// The allowed date cannot be zero
if (allowedAt == 0) revert TaskInvalidAllowedDate(mode, allowedAt);
// If the mode is "on-day", the allowed date must be valid for every month, then the allowed day cannot be
// larger than 28. But if the mode is "on-last-day", the allowed date day must be the last day of the month
if (mode == uint8(Mode.OnDay)) {
if (allowedAt.getDay() > 28) revert TaskInvalidAllowedDate(mode, allowedAt);
} else if (mode == uint8(Mode.OnLastMonthDay)) {
if (allowedAt.getDay() != allowedAt.getDaysInMonth()) revert TaskInvalidAllowedDate(mode, allowedAt);
} else {
revert TaskInvalidFrequencyMode(mode);
}
}
_mode = Mode(mode);
_frequency = frequency;
_allowedAt = allowedAt;
_window = window;
emit TimeLockSet(mode, frequency, allowedAt, window);
}
/**
* @dev Sets the time-lock execution allowed timestamp
* @param allowedAt New execution allowed timestamp to be set
*/
function _setTimeLockAllowedAt(uint256 allowedAt) internal {
_allowedAt = allowedAt;
emit TimeLockAllowedAtSet(allowedAt);
}
/**
* @dev Tells the corresponding allowed date based on a current timestamp
*/
function _getCurrentAllowedDate(uint256 allowedAt, uint256 day) private view returns (uint256) {
(uint256 year, uint256 month, ) = block.timestamp.timestampToDate();
return _getAllowedDateFor(allowedAt, year, month, day);
}
/**
* @dev Tells the next allowed date based on a current allowed date considering a number of months to increase
*/
function _getNextAllowedDate(uint256 allowedAt, uint256 monthsToIncrease) private view returns (uint256) {
(uint256 year, uint256 month, uint256 day) = allowedAt.timestampToDate();
uint256 increasedMonth = month + monthsToIncrease;
uint256 nextMonth = increasedMonth % 12;
uint256 nextYear = year + (increasedMonth / 12);
uint256 nextDay = _mode == Mode.OnLastMonthDay ? DateTime._getDaysInMonth(nextYear, nextMonth) : day;
return _getAllowedDateFor(allowedAt, nextYear, nextMonth, nextDay);
}
/**
* @dev Builds an allowed date using a specific year, month, and day
*/
function _getAllowedDateFor(uint256 allowedAt, uint256 year, uint256 month, uint256 day)
private
pure
returns (uint256)
{
return
DateTime.timestampFromDateTime(
year,
month,
day,
allowedAt.getHour(),
allowedAt.getMinute(),
allowedAt.getSecond()
);
}
}// 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.8.3;
import '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';
import '@mimic-fi/v3-authorizer/contracts/Authorized.sol';
import '../interfaces/base/ITokenIndexedTask.sol';
/**
* @dev Token indexed task. It defines a token acceptance list to tell which are the tokens supported by the
* task. Tokens acceptance can be configured either as an allow list or as a deny list.
*/
abstract contract TokenIndexedTask is ITokenIndexedTask, Authorized {
using EnumerableSet for EnumerableSet.AddressSet;
// Acceptance list type
TokensAcceptanceType public override tokensAcceptanceType;
// Enumerable set of tokens included in the acceptance list
EnumerableSet.AddressSet internal _tokens;
/**
* @dev Token index config. Only used in the initializer.
* @param acceptanceType Token acceptance type to be set
* @param tokens List of token addresses to be set for the acceptance list
*/
struct TokenIndexConfig {
TokensAcceptanceType acceptanceType;
address[] tokens;
}
/**
* @dev Initializes the token indexed task. It does not call upper contracts initializers.
* @param config Token indexed task config
*/
function __TokenIndexedTask_init(TokenIndexConfig memory config) internal onlyInitializing {
__TokenIndexedTask_init_unchained(config);
}
/**
* @dev Initializes the token indexed task. It does call upper contracts initializers.
* @param config Token indexed task config
*/
function __TokenIndexedTask_init_unchained(TokenIndexConfig memory config) internal onlyInitializing {
_setTokensAcceptanceType(config.acceptanceType);
for (uint256 i = 0; i < config.tokens.length; i++) {
_setTokenAcceptanceList(config.tokens[i], true);
}
}
/**
* @dev Tells whether a token is allowed or not
* @param token Address of the token being queried
*/
function isTokenAllowed(address token) public view override returns (bool) {
bool containsToken = _tokens.contains(token);
return tokensAcceptanceType == TokensAcceptanceType.AllowList ? containsToken : !containsToken;
}
/**
* @dev Sets the tokens acceptance type of the task
* @param newTokensAcceptanceType New token acceptance type to be set
*/
function setTokensAcceptanceType(TokensAcceptanceType newTokensAcceptanceType)
external
override
authP(authParams(uint8(newTokensAcceptanceType)))
{
_setTokensAcceptanceType(newTokensAcceptanceType);
}
/**
* @dev Updates the list of tokens of the tokens acceptance list
* @param tokens List of tokens to be updated from the acceptance list
* @param added Whether each of the given tokens should be added or removed from the list
*/
function setTokensAcceptanceList(address[] memory tokens, bool[] memory added) external override auth {
if (tokens.length != added.length) revert TaskAcceptanceInputLengthMismatch();
for (uint256 i = 0; i < tokens.length; i++) {
_setTokenAcceptanceList(tokens[i], added[i]);
}
}
/**
* @dev Before token indexed task hook
*/
function _beforeTokenIndexedTask(address token, uint256) internal virtual {
if (!isTokenAllowed(token)) revert TaskTokenNotAllowed(token);
}
/**
* @dev After token indexed task hook
*/
function _afterTokenIndexedTask(address token, uint256) internal virtual {
// solhint-disable-previous-line no-empty-blocks
}
/**
* @dev Sets the tokens acceptance type of the task
* @param newTokensAcceptanceType New token acceptance type to be set
*/
function _setTokensAcceptanceType(TokensAcceptanceType newTokensAcceptanceType) internal {
tokensAcceptanceType = newTokensAcceptanceType;
emit TokensAcceptanceTypeSet(newTokensAcceptanceType);
}
/**
* @dev Updates a token from the tokens acceptance list
* @param token Token to be updated from the acceptance list
* @param added Whether the token should be added or removed from the list
*/
function _setTokenAcceptanceList(address token, bool added) internal {
if (token == address(0)) revert TaskAcceptanceTokenZero();
added ? _tokens.add(token) : _tokens.remove(token);
emit TokensAcceptanceListSet(token, added);
}
}// 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.8.3;
import '@mimic-fi/v3-authorizer/contracts/Authorized.sol';
import '@mimic-fi/v3-helpers/contracts/math/FixedPoint.sol';
import '../interfaces/base/ITokenThresholdTask.sol';
/**
* @dev Token threshold task. It mainly works with token threshold configs that can be used to tell if
* a specific token amount is compliant with certain minimum or maximum values. Token threshold tasks
* make use of a default threshold config as a fallback in case there is no custom threshold defined for the token
* being evaluated.
*/
abstract contract TokenThresholdTask is ITokenThresholdTask, Authorized {
using FixedPoint for uint256;
// Default threshold
Threshold internal _defaultThreshold;
// Custom thresholds per token
mapping (address => Threshold) internal _customThresholds;
/**
* @dev Threshold defined by a token address and min/max values
*/
struct Threshold {
address token;
uint256 min;
uint256 max;
}
/**
* @dev Custom token threshold config. Only used in the initializer.
*/
struct CustomThresholdConfig {
address token;
Threshold threshold;
}
/**
* @dev Token threshold config. Only used in the initializer.
* @param defaultThreshold Default threshold to be set
* @param customThresholdConfigs List of custom threshold configs to be set
*/
struct TokenThresholdConfig {
Threshold defaultThreshold;
CustomThresholdConfig[] customThresholdConfigs;
}
/**
* @dev Initializes the token threshold task. It does not call upper contracts initializers.
* @param config Token threshold task config
*/
function __TokenThresholdTask_init(TokenThresholdConfig memory config) internal onlyInitializing {
__TokenThresholdTask_init_unchained(config);
}
/**
* @dev Initializes the token threshold task. It does call upper contracts initializers.
* @param config Token threshold task config
*/
function __TokenThresholdTask_init_unchained(TokenThresholdConfig memory config) internal onlyInitializing {
Threshold memory defaultThreshold = config.defaultThreshold;
_setDefaultTokenThreshold(defaultThreshold.token, defaultThreshold.min, defaultThreshold.max);
for (uint256 i = 0; i < config.customThresholdConfigs.length; i++) {
CustomThresholdConfig memory customThresholdConfig = config.customThresholdConfigs[i];
Threshold memory custom = customThresholdConfig.threshold;
_setCustomTokenThreshold(customThresholdConfig.token, custom.token, custom.min, custom.max);
}
}
/**
* @dev Tells the default token threshold
*/
function defaultTokenThreshold() external view override returns (address thresholdToken, uint256 min, uint256 max) {
Threshold memory threshold = _defaultThreshold;
return (threshold.token, threshold.min, threshold.max);
}
/**
* @dev Tells the token threshold defined for a specific token
* @param token Address of the token being queried
*/
function customTokenThreshold(address token)
external
view
override
returns (address thresholdToken, uint256 min, uint256 max)
{
Threshold memory threshold = _customThresholds[token];
return (threshold.token, threshold.min, threshold.max);
}
/**
* @dev Tells the threshold that should be used for a token, it prioritizes custom thresholds over the default one
* @param token Address of the token being queried
*/
function getTokenThreshold(address token)
external
view
virtual
override
returns (address thresholdToken, uint256 min, uint256 max)
{
Threshold memory threshold = _getTokenThreshold(token);
return (threshold.token, threshold.min, threshold.max);
}
/**
* @dev Sets a new default threshold config
* @param thresholdToken New threshold token to be set
* @param min New threshold minimum to be set
* @param max New threshold maximum to be set
*/
function setDefaultTokenThreshold(address thresholdToken, uint256 min, uint256 max)
external
override
authP(authParams(thresholdToken, min, max))
{
_setDefaultTokenThreshold(thresholdToken, min, max);
}
/**
* @dev Sets a custom token threshold
* @param token Address of the token to set a custom threshold for
* @param thresholdToken New custom threshold token to be set
* @param min New custom threshold minimum to be set
* @param max New custom threshold maximum to be set
*/
function setCustomTokenThreshold(address token, address thresholdToken, uint256 min, uint256 max)
external
override
authP(authParams(token, thresholdToken, min, max))
{
_setCustomTokenThreshold(token, thresholdToken, min, max);
}
/**
* @dev Fetches a base/quote price
*/
function _getPrice(address base, address quote) internal view virtual returns (uint256);
/**
* @dev Tells the threshold that should be used for a token, it prioritizes custom thresholds over the default one
* @param token Address of the token being queried
*/
function _getTokenThreshold(address token) internal view returns (Threshold memory) {
Threshold storage customThreshold = _customThresholds[token];
return customThreshold.token == address(0) ? _defaultThreshold : customThreshold;
}
/**
* @dev Before token threshold task hook
*/
function _beforeTokenThresholdTask(address token, uint256 amount) internal virtual {
Threshold memory threshold = _getTokenThreshold(token);
if (threshold.token == address(0)) return;
uint256 convertedAmount = threshold.token == token ? amount : amount.mulDown(_getPrice(token, threshold.token));
bool isValid = convertedAmount >= threshold.min && (threshold.max == 0 || convertedAmount <= threshold.max);
if (!isValid) revert TaskTokenThresholdNotMet(threshold.token, convertedAmount, threshold.min, threshold.max);
}
/**
* @dev After token threshold task hook
*/
function _afterTokenThresholdTask(address, uint256) internal virtual {
// solhint-disable-previous-line no-empty-blocks
}
/**
* @dev Sets a new default threshold config
* @param thresholdToken New threshold token to be set
* @param min New threshold minimum to be set
* @param max New threshold maximum to be set
*/
function _setDefaultTokenThreshold(address thresholdToken, uint256 min, uint256 max) internal {
_setTokenThreshold(_defaultThreshold, thresholdToken, min, max);
emit DefaultTokenThresholdSet(thresholdToken, min, max);
}
/**
* @dev Sets a custom of tokens thresholds
* @param token Address of the token to set a custom threshold for
* @param thresholdToken New custom threshold token to be set
* @param min New custom threshold minimum to be set
* @param max New custom threshold maximum to be set
*/
function _setCustomTokenThreshold(address token, address thresholdToken, uint256 min, uint256 max) internal {
if (token == address(0)) revert TaskThresholdTokenZero();
_setTokenThreshold(_customThresholds[token], thresholdToken, min, max);
emit CustomTokenThresholdSet(token, thresholdToken, min, max);
}
/**
* @dev Sets a threshold
* @param threshold Threshold to be updated
* @param token New threshold token to be set
* @param min New threshold minimum to be set
* @param max New threshold maximum to be set
*/
function _setTokenThreshold(Threshold storage threshold, address token, uint256 min, uint256 max) private {
// If there is no threshold, all values must be zero
bool isZeroThreshold = token == address(0) && min == 0 && max == 0;
bool isNonZeroThreshold = token != address(0) && (max == 0 || max >= min);
if (!isZeroThreshold && !isNonZeroThreshold) revert TaskInvalidThresholdInput(token, min, max);
threshold.token = token;
threshold.min = min;
threshold.max = max;
}
}// 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.8.17;
import '@mimic-fi/v3-authorizer/contracts/Authorized.sol';
import '@mimic-fi/v3-helpers/contracts/math/FixedPoint.sol';
import '../interfaces/base/IVolumeLimitedTask.sol';
/**
* @dev Volume limit config for tasks. It allows setting volume limit per period of time.
*/
abstract contract VolumeLimitedTask is IVolumeLimitedTask, Authorized {
using FixedPoint for uint256;
// Default volume limit
VolumeLimit internal _defaultVolumeLimit;
// Custom volume limits per token
mapping (address => VolumeLimit) internal _customVolumeLimits;
/**
* @dev Volume limit config
* @param token Address to measure the volume limit
*/
struct VolumeLimit {
address token;
uint256 amount;
uint256 accrued;
uint256 period;
uint256 nextResetTime;
}
/**
* @dev Volume limit params. Only used in the initializer.
*/
struct VolumeLimitParams {
address token;
uint256 amount;
uint256 period;
}
/**
* @dev Custom token volume limit config. Only used in the initializer.
*/
struct CustomVolumeLimitConfig {
address token;
VolumeLimitParams volumeLimit;
}
/**
* @dev Volume limit config. Only used in the initializer.
*/
struct VolumeLimitConfig {
VolumeLimitParams defaultVolumeLimit;
CustomVolumeLimitConfig[] customVolumeLimitConfigs;
}
/**
* @dev Initializes the volume limited task. It does call upper contracts initializers.
* @param config Volume limited task config
*/
function __VolumeLimitedTask_init(VolumeLimitConfig memory config) internal onlyInitializing {
__VolumeLimitedTask_init_unchained(config);
}
/**
* @dev Initializes the volume limited task. It does not call upper contracts initializers.
* @param config Volume limited task config
*/
function __VolumeLimitedTask_init_unchained(VolumeLimitConfig memory config) internal onlyInitializing {
VolumeLimitParams memory defaultLimit = config.defaultVolumeLimit;
_setDefaultVolumeLimit(defaultLimit.token, defaultLimit.amount, defaultLimit.period);
for (uint256 i = 0; i < config.customVolumeLimitConfigs.length; i++) {
CustomVolumeLimitConfig memory customVolumeLimitConfig = config.customVolumeLimitConfigs[i];
VolumeLimitParams memory custom = customVolumeLimitConfig.volumeLimit;
_setCustomVolumeLimit(customVolumeLimitConfig.token, custom.token, custom.amount, custom.period);
}
}
/**
* @dev Tells the default volume limit set
*/
function defaultVolumeLimit()
external
view
override
returns (address limitToken, uint256 amount, uint256 accrued, uint256 period, uint256 nextResetTime)
{
VolumeLimit memory limit = _defaultVolumeLimit;
return (limit.token, limit.amount, limit.accrued, limit.period, limit.nextResetTime);
}
/**
* @dev Tells the custom volume limit set for a specific token
* @param token Address of the token being queried
*/
function customVolumeLimit(address token)
external
view
override
returns (address limitToken, uint256 amount, uint256 accrued, uint256 period, uint256 nextResetTime)
{
VolumeLimit memory limit = _customVolumeLimits[token];
return (limit.token, limit.amount, limit.accrued, limit.period, limit.nextResetTime);
}
/**
* @dev Tells the volume limit that should be used for a token, it prioritizes custom limits over the default one
* @param token Address of the token being queried
*/
function getVolumeLimit(address token)
external
view
override
returns (address limitToken, uint256 amount, uint256 accrued, uint256 period, uint256 nextResetTime)
{
VolumeLimit memory limit = _getVolumeLimit(token);
return (limit.token, limit.amount, limit.accrued, limit.period, limit.nextResetTime);
}
/**
* @dev Sets a the default volume limit config
* @param limitToken Address of the token to measure the volume limit
* @param limitAmount Amount of tokens to be applied for the volume limit
* @param limitPeriod Frequency to Amount of tokens to be applied for the volume limit
*/
function setDefaultVolumeLimit(address limitToken, uint256 limitAmount, uint256 limitPeriod)
external
override
authP(authParams(limitToken, limitAmount, limitPeriod))
{
_setDefaultVolumeLimit(limitToken, limitAmount, limitPeriod);
}
/**
* @dev Sets a custom volume limit
* @param token Address of the token to set a custom volume limit for
* @param limitToken Address of the token to measure the volume limit
* @param limitAmount Amount of tokens to be applied for the volume limit
* @param limitPeriod Frequency to Amount of tokens to be applied for the volume limit
*/
function setCustomVolumeLimit(address token, address limitToken, uint256 limitAmount, uint256 limitPeriod)
external
override
authP(authParams(token, limitToken, limitAmount, limitPeriod))
{
_setCustomVolumeLimit(token, limitToken, limitAmount, limitPeriod);
}
/**
* @dev Fetches a base/quote price
*/
function _getPrice(address base, address quote) internal view virtual returns (uint256);
/**
* @dev Tells the volume limit that should be used for a token, it prioritizes custom limits over the default one
* @param token Address of the token being queried
*/
function _getVolumeLimit(address token) internal view returns (VolumeLimit storage) {
VolumeLimit storage customLimit = _customVolumeLimits[token];
return customLimit.token == address(0) ? _defaultVolumeLimit : customLimit;
}
/**
* @dev Before volume limited task hook
*/
function _beforeVolumeLimitedTask(address token, uint256 amount) internal virtual {
VolumeLimit memory limit = _getVolumeLimit(token);
if (limit.token == address(0)) return;
uint256 amountInLimitToken = limit.token == token ? amount : amount.mulDown(_getPrice(token, limit.token));
uint256 processedVolume = amountInLimitToken + (block.timestamp < limit.nextResetTime ? limit.accrued : 0);
if (processedVolume > limit.amount) revert TaskVolumeLimitExceeded(limit.token, limit.amount, processedVolume);
}
/**
* @dev After volume limited task hook
*/
function _afterVolumeLimitedTask(address token, uint256 amount) internal virtual {
VolumeLimit storage limit = _getVolumeLimit(token);
if (limit.token == address(0)) return;
uint256 amountInLimitToken = limit.token == token ? amount : amount.mulDown(_getPrice(token, limit.token));
if (block.timestamp >= limit.nextResetTime) {
limit.accrued = 0;
limit.nextResetTime = block.timestamp + limit.period;
}
limit.accrued += amountInLimitToken;
}
/**
* @dev Sets the default volume limit
* @param limitToken Address of the token to measure the volume limit
* @param limitAmount Amount of tokens to be applied for the volume limit
* @param limitPeriod Frequency to Amount of tokens to be applied for the volume limit
*/
function _setDefaultVolumeLimit(address limitToken, uint256 limitAmount, uint256 limitPeriod) internal {
_setVolumeLimit(_defaultVolumeLimit, limitToken, limitAmount, limitPeriod);
emit DefaultVolumeLimitSet(limitToken, limitAmount, limitPeriod);
}
/**
* @dev Sets a custom volume limit
* @param token Address of the token to set a custom volume limit for
* @param limitToken Address of the token to measure the volume limit
* @param limitAmount Amount of tokens to be applied for the volume limit
* @param limitPeriod Frequency to Amount of tokens to be applied for the volume limit
*/
function _setCustomVolumeLimit(address token, address limitToken, uint256 limitAmount, uint256 limitPeriod)
internal
{
if (token == address(0)) revert TaskVolumeLimitTokenZero();
_setVolumeLimit(_customVolumeLimits[token], limitToken, limitAmount, limitPeriod);
emit CustomVolumeLimitSet(token, limitToken, limitAmount, limitPeriod);
}
/**
* @dev Sets a volume limit
* @param limit Volume limit to be updated
* @param token Address of the token to measure the volume limit
* @param amount Amount of tokens to be applied for the volume limit
* @param period Frequency to Amount of tokens to be applied for the volume limit
*/
function _setVolumeLimit(VolumeLimit storage limit, address token, uint256 amount, uint256 period) private {
// If there is no limit, all values must be zero
bool isZeroLimit = token == address(0) && amount == 0 && period == 0;
bool isNonZeroLimit = token != address(0) && amount > 0 && period > 0;
if (!isZeroLimit && !isNonZeroLimit) revert TaskInvalidVolumeLimitInput(token, amount, period);
// Changing the period only affects the end time of the next period, but not the end date of the current one
limit.period = period;
// Changing the amount does not affect the totalizator, it only applies when updating the accrued amount.
// Note that it can happen that the new amount is lower than the accrued amount if the amount is lowered.
// However, there shouldn't be any accounting issues with that.
limit.amount = amount;
// Therefore, only clean the totalizators if the limit is being removed
if (isZeroLimit) {
limit.accrued = 0;
limit.nextResetTime = 0;
} else {
// If limit is not zero, set the next reset time if it wasn't set already
// Otherwise, if the token is being changed the accrued amount must be updated accordingly
if (limit.nextResetTime == 0) {
limit.accrued = 0;
limit.nextResetTime = block.timestamp + period;
} else if (limit.token != token) {
uint256 price = _getPrice(limit.token, token);
limit.accrued = limit.accrued.mulDown(price);
}
}
// Finally simply set the new requested token
limit.token = token;
}
}// 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.8.0;
import '@mimic-fi/v3-authorizer/contracts/interfaces/IAuthorized.sol';
/**
* @dev Base task interface
*/
interface IBaseTask is IAuthorized {
// Execution type serves for relayers in order to distinguish how each task must be executed
// solhint-disable-next-line func-name-mixedcase
function EXECUTION_TYPE() external view returns (bytes32);
/**
* @dev The balance connectors are the same
*/
error TaskSameBalanceConnectors(bytes32 connectorId);
/**
* @dev The smart vault's price oracle is not set
*/
error TaskSmartVaultPriceOracleNotSet(address smartVault);
/**
* @dev Emitted every time a task is executed
*/
event Executed();
/**
* @dev Emitted every time the balance connectors are set
*/
event BalanceConnectorsSet(bytes32 indexed previous, bytes32 indexed next);
/**
* @dev Tells the address of the Smart Vault tied to it, it cannot be changed
*/
function smartVault() external view returns (address);
/**
* @dev Tells the address from where the token amounts to execute this task are fetched.
* This address must be the Smart Vault in case the previous balance connector is set.
*/
function getTokensSource() external view returns (address);
/**
* @dev Tells the amount a task should use for a token
* @param token Address of the token being queried
*/
function getTaskAmount(address token) external view returns (uint256);
/**
* @dev Tells the previous and next balance connectors id of the previous task in the workflow
*/
function getBalanceConnectors() external view returns (bytes32 previous, bytes32 next);
/**
* @dev Sets the balance connector IDs
* @param previous Balance connector id of the previous task in the workflow
* @param next Balance connector id of the next task in the workflow
*/
function setBalanceConnectors(bytes32 previous, bytes32 next) 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.8.0;
import './IBaseTask.sol';
/**
* @dev Gas limited task interface
*/
interface IGasLimitedTask is IBaseTask {
/**
* @dev The tx initial gas cache has not been initialized
*/
error TaskGasNotInitialized();
/**
* @dev The gas price used is greater than the limit
*/
error TaskGasPriceLimitExceeded(uint256 gasPrice, uint256 gasPriceLimit);
/**
* @dev The priority fee used is greater than the priority fee limit
*/
error TaskPriorityFeeLimitExceeded(uint256 priorityFee, uint256 priorityFeeLimit);
/**
* @dev The transaction cost is greater than the transaction cost limit
*/
error TaskTxCostLimitExceeded(uint256 txCost, uint256 txCostLimit);
/**
* @dev The transaction cost percentage is greater than the transaction cost limit percentage
*/
error TaskTxCostLimitPctExceeded(uint256 txCostPct, uint256 txCostLimitPct);
/**
* @dev The new transaction cost limit percentage is greater than one
*/
error TaskTxCostLimitPctAboveOne();
/**
* @dev Emitted every time the gas limits are set
*/
event GasLimitsSet(uint256 gasPriceLimit, uint256 priorityFeeLimit, uint256 txCostLimit, uint256 txCostLimitPct);
/**
* @dev Tells the gas limits config
*/
function getGasLimits()
external
view
returns (uint256 gasPriceLimit, uint256 priorityFeeLimit, uint256 txCostLimit, uint256 txCostLimitPct);
/**
* @dev Sets the gas limits config
* @param newGasPriceLimit New gas price limit to be set
* @param newPriorityFeeLimit New priority fee limit to be set
* @param newTxCostLimit New tx cost limit to be set
* @param newTxCostLimitPct New tx cost percentage limit to be set
*/
function setGasLimits(
uint256 newGasPriceLimit,
uint256 newPriorityFeeLimit,
uint256 newTxCostLimit,
uint256 newTxCostLimitPct
) 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.8.0;
import './IBaseTask.sol';
/**
* @dev Pausable task interface
*/
interface IPausableTask is IBaseTask {
/**
* @dev The task is paused
*/
error TaskPaused();
/**
* @dev The task is unpaused
*/
error TaskUnpaused();
/**
* @dev Emitted every time a task is paused
*/
event Paused();
/**
* @dev Emitted every time a task is unpaused
*/
event Unpaused();
/**
* @dev Tells the task is paused or not
*/
function isPaused() external view returns (bool);
/**
* @dev Pauses a task
*/
function pause() external;
/**
* @dev Unpauses a task
*/
function unpause() 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.8.0;
import './IBaseTask.sol';
/**
* @dev Time-locked task interface
*/
interface ITimeLockedTask is IBaseTask {
/**
* @dev The time lock frequency mode requested is invalid
*/
error TaskInvalidFrequencyMode(uint8 mode);
/**
* @dev The time lock frequency is not valid
*/
error TaskInvalidFrequency(uint8 mode, uint256 frequency);
/**
* @dev The time lock allowed date is not valid
*/
error TaskInvalidAllowedDate(uint8 mode, uint256 date);
/**
* @dev The time lock allowed window is not valid
*/
error TaskInvalidAllowedWindow(uint8 mode, uint256 window);
/**
* @dev The time lock is still active
*/
error TaskTimeLockActive(uint256 currentTimestamp, uint256 expiration);
/**
* @dev Emitted every time a new time lock is set
*/
event TimeLockSet(uint8 mode, uint256 frequency, uint256 allowedAt, uint256 window);
/**
* @dev Emitted every time a new expiration timestamp is set
*/
event TimeLockAllowedAtSet(uint256 allowedAt);
/**
* @dev Tells all the time-lock related information
*/
function getTimeLock() external view returns (uint8 mode, uint256 frequency, uint256 allowedAt, uint256 window);
/**
* @dev Sets the time-lock
* @param mode Time lock mode
* @param frequency Time lock frequency
* @param allowedAt Future timestamp since when the task can be executed
* @param window Period in seconds during when a time-locked task can be executed since the allowed timestamp
*/
function setTimeLock(uint8 mode, uint256 frequency, uint256 allowedAt, uint256 window) 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.8.0;
import './IBaseTask.sol';
/**
* @dev Token indexed task interface
*/
interface ITokenIndexedTask is IBaseTask {
/**
* @dev Acceptance list types: either deny-list to express "all except" or allow-list to express "only"
*/
enum TokensAcceptanceType {
DenyList,
AllowList
}
/**
* @dev The acceptance token is zero
*/
error TaskAcceptanceTokenZero();
/**
* @dev The tokens acceptance input length mismatch
*/
error TaskAcceptanceInputLengthMismatch();
/**
* @dev The token is not allowed
*/
error TaskTokenNotAllowed(address token);
/**
* @dev Emitted every time a tokens acceptance type is set
*/
event TokensAcceptanceTypeSet(TokensAcceptanceType acceptanceType);
/**
* @dev Emitted every time a token is added or removed from the acceptance list
*/
event TokensAcceptanceListSet(address indexed token, bool added);
/**
* @dev Tells the acceptance type of the config
*/
function tokensAcceptanceType() external view returns (TokensAcceptanceType);
/**
* @dev Tells whether a token is allowed or not
* @param token Address of the token being queried
*/
function isTokenAllowed(address token) external view returns (bool);
/**
* @dev Sets the tokens acceptance type of the task
* @param newTokensAcceptanceType New token acceptance type to be set
*/
function setTokensAcceptanceType(TokensAcceptanceType newTokensAcceptanceType) external;
/**
* @dev Updates the list of tokens of the tokens acceptance list
* @param tokens List of tokens to be updated from the acceptance list
* @param added Whether each of the given tokens should be added or removed from the list
*/
function setTokensAcceptanceList(address[] memory tokens, bool[] memory added) 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 External 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 External License for more details.
// You should have received a copy of the GNU General External License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
pragma solidity >=0.8.0;
import './IBaseTask.sol';
/**
* @dev Token threshold task interface
*/
interface ITokenThresholdTask is IBaseTask {
/**
* @dev The token threshold token is zero
*/
error TaskThresholdTokenZero();
/**
* @dev The token threshold to be set is invalid
*/
error TaskInvalidThresholdInput(address token, uint256 min, uint256 max);
/**
* @dev The token threshold has not been met
*/
error TaskTokenThresholdNotMet(address token, uint256 amount, uint256 min, uint256 max);
/**
* @dev Emitted every time a default threshold is set
*/
event DefaultTokenThresholdSet(address token, uint256 min, uint256 max);
/**
* @dev Emitted every time a token threshold is set
*/
event CustomTokenThresholdSet(address indexed token, address thresholdToken, uint256 min, uint256 max);
/**
* @dev Tells the default token threshold
*/
function defaultTokenThreshold() external view returns (address thresholdToken, uint256 min, uint256 max);
/**
* @dev Tells the custom threshold defined for a specific token
* @param token Address of the token being queried
*/
function customTokenThreshold(address token)
external
view
returns (address thresholdToken, uint256 min, uint256 max);
/**
* @dev Tells the threshold that should be used for a token
* @param token Address of the token being queried
*/
function getTokenThreshold(address token) external view returns (address thresholdToken, uint256 min, uint256 max);
/**
* @dev Sets a new default threshold config
* @param thresholdToken New threshold token to be set
* @param min New threshold minimum to be set
* @param max New threshold maximum to be set
*/
function setDefaultTokenThreshold(address thresholdToken, uint256 min, uint256 max) external;
/**
* @dev Sets a custom token threshold
* @param token Address of the token to set a custom threshold
* @param thresholdToken New custom threshold token to be set
* @param min New custom threshold minimum to be set
* @param max New custom threshold maximum to be set
*/
function setCustomTokenThreshold(address token, address thresholdToken, uint256 min, uint256 max) 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.8.0;
import './IBaseTask.sol';
/**
* @dev Volume limited task interface
*/
interface IVolumeLimitedTask is IBaseTask {
/**
* @dev The volume limit token is zero
*/
error TaskVolumeLimitTokenZero();
/**
* @dev The volume limit to be set is invalid
*/
error TaskInvalidVolumeLimitInput(address token, uint256 amount, uint256 period);
/**
* @dev The volume limit has been exceeded
*/
error TaskVolumeLimitExceeded(address token, uint256 limit, uint256 volume);
/**
* @dev Emitted every time a default volume limit is set
*/
event DefaultVolumeLimitSet(address indexed limitToken, uint256 amount, uint256 period);
/**
* @dev Emitted every time a custom volume limit is set
*/
event CustomVolumeLimitSet(address indexed token, address indexed limitToken, uint256 amount, uint256 period);
/**
* @dev Tells the default volume limit set
*/
function defaultVolumeLimit()
external
view
returns (address limitToken, uint256 amount, uint256 accrued, uint256 period, uint256 nextResetTime);
/**
* @dev Tells the custom volume limit set for a specific token
* @param token Address of the token being queried
*/
function customVolumeLimit(address token)
external
view
returns (address limitToken, uint256 amount, uint256 accrued, uint256 period, uint256 nextResetTime);
/**
* @dev Tells the volume limit that should be used for a token
* @param token Address of the token being queried
*/
function getVolumeLimit(address token)
external
view
returns (address limitToken, uint256 amount, uint256 accrued, uint256 period, uint256 nextResetTime);
/**
* @dev Sets a the default volume limit config
* @param limitToken Address of the token to measure the volume limit
* @param limitAmount Amount of tokens to be applied for the volume limit
* @param limitPeriod Frequency to Amount of tokens to be applied for the volume limit
*/
function setDefaultVolumeLimit(address limitToken, uint256 limitAmount, uint256 limitPeriod) external;
/**
* @dev Sets a custom volume limit
* @param token Address of the token to set a custom volume limit for
* @param limitToken Address of the token to measure the volume limit
* @param limitAmount Amount of tokens to be applied for the volume limit
* @param limitPeriod Frequency to Amount of tokens to be applied for the volume limit
*/
function setCustomVolumeLimit(address token, address limitToken, uint256 limitAmount, uint256 limitPeriod) 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.8.0;
import './base/IBaseTask.sol';
import './base/IGasLimitedTask.sol';
import './base/ITimeLockedTask.sol';
import './base/ITokenIndexedTask.sol';
import './base/ITokenThresholdTask.sol';
import './base/IVolumeLimitedTask.sol';
// solhint-disable no-empty-blocks
/**
* @dev Task interface
*/
interface ITask is
IBaseTask,
IGasLimitedTask,
ITimeLockedTask,
ITokenIndexedTask,
ITokenThresholdTask,
IVolumeLimitedTask
{
}// 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.8.0;
import './interfaces/ITask.sol';
import './base/BaseTask.sol';
import './base/PausableTask.sol';
import './base/GasLimitedTask.sol';
import './base/TimeLockedTask.sol';
import './base/TokenIndexedTask.sol';
import './base/TokenThresholdTask.sol';
import './base/VolumeLimitedTask.sol';
/**
* @title Task
* @dev Shared components across all tasks
*/
abstract contract Task is
ITask,
BaseTask,
PausableTask,
GasLimitedTask,
TimeLockedTask,
TokenIndexedTask,
TokenThresholdTask,
VolumeLimitedTask
{
/**
* @dev Task config. Only used in the initializer.
*/
struct TaskConfig {
BaseConfig baseConfig;
GasLimitConfig gasLimitConfig;
TimeLockConfig timeLockConfig;
TokenIndexConfig tokenIndexConfig;
TokenThresholdConfig tokenThresholdConfig;
VolumeLimitConfig volumeLimitConfig;
}
/**
* @dev Initializes the task. It does call upper contracts initializers.
* @param config Task config
*/
function __Task_init(TaskConfig memory config) internal onlyInitializing {
__BaseTask_init(config.baseConfig);
__PausableTask_init();
__GasLimitedTask_init(config.gasLimitConfig);
__TimeLockedTask_init(config.timeLockConfig);
__TokenIndexedTask_init(config.tokenIndexConfig);
__TokenThresholdTask_init(config.tokenThresholdConfig);
__VolumeLimitedTask_init(config.volumeLimitConfig);
__Task_init_unchained(config);
}
/**
* @dev Initializes the task. It does not call upper contracts initializers.
* @param config Task config
*/
function __Task_init_unchained(TaskConfig memory config) internal onlyInitializing {
// solhint-disable-previous-line no-empty-blocks
}
/**
* @dev Fetches a base/quote price
*/
function _getPrice(address base, address quote)
internal
view
override(BaseTask, GasLimitedTask, TokenThresholdTask, VolumeLimitedTask)
returns (uint256)
{
return BaseTask._getPrice(base, quote);
}
/**
* @dev Before task hook
*/
function _beforeTask(address token, uint256 amount) internal virtual {
_beforeBaseTask(token, amount);
_beforePausableTask(token, amount);
_beforeGasLimitedTask(token, amount);
_beforeTimeLockedTask(token, amount);
_beforeTokenIndexedTask(token, amount);
_beforeTokenThresholdTask(token, amount);
_beforeVolumeLimitedTask(token, amount);
}
/**
* @dev After task hook
*/
function _afterTask(address token, uint256 amount) internal virtual {
_afterVolumeLimitedTask(token, amount);
_afterTokenThresholdTask(token, amount);
_afterTokenIndexedTask(token, amount);
_afterTimeLockedTask(token, amount);
_afterGasLimitedTask(token, amount);
_afterPausableTask(token, amount);
_afterBaseTask(token, amount);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (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. Equivalent to `reinitializer(1)`.
*/
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.
*
* `initializer` is equivalent to `reinitializer(1)`, so 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.
*
* 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.
*/
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.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.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 functionCall(target, data, "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");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(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) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason 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 {
// 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.9.0) (token/ERC20/extensions/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.9.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.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/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;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
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));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
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");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
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");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation 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).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// 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 cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.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
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [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://consensys.net/diligence/blog/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.8.0/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.9.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.
*
* ```solidity
* 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: MIT
pragma solidity ^0.8.0;
// ----------------------------------------------------------------------------
// DateTime Library v2.0
//
// A gas-efficient Solidity date and time library
//
// https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary
//
// Tested date range 1970/01/01 to 2345/12/31
//
// Conventions:
// Unit | Range | Notes
// :-------- |:-------------:|:-----
// timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC
// year | 1970 ... 2345 |
// month | 1 ... 12 |
// day | 1 ... 31 |
// hour | 0 ... 23 |
// minute | 0 ... 59 |
// second | 0 ... 59 |
// dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday
//
//
// Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence.
// ----------------------------------------------------------------------------
library DateTime {
uint256 constant SECONDS_PER_DAY = 24 * 60 * 60;
uint256 constant SECONDS_PER_HOUR = 60 * 60;
uint256 constant SECONDS_PER_MINUTE = 60;
int256 constant OFFSET19700101 = 2440588;
uint256 constant DOW_MON = 1;
uint256 constant DOW_TUE = 2;
uint256 constant DOW_WED = 3;
uint256 constant DOW_THU = 4;
uint256 constant DOW_FRI = 5;
uint256 constant DOW_SAT = 6;
uint256 constant DOW_SUN = 7;
// ------------------------------------------------------------------------
// Calculate the number of days from 1970/01/01 to year/month/day using
// the date conversion algorithm from
// http://aa.usno.navy.mil/faq/docs/JD_Formula.php
// and subtracting the offset 2440588 so that 1970/01/01 is day 0
//
// days = day
// - 32075
// + 1461 * (year + 4800 + (month - 14) / 12) / 4
// + 367 * (month - 2 - (month - 14) / 12 * 12) / 12
// - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4
// - offset
// ------------------------------------------------------------------------
function _daysFromDate(uint256 year, uint256 month, uint256 day) internal pure returns (uint256 _days) {
require(year >= 1970);
int256 _year = int256(year);
int256 _month = int256(month);
int256 _day = int256(day);
int256 __days = _day - 32075 + (1461 * (_year + 4800 + (_month - 14) / 12)) / 4
+ (367 * (_month - 2 - ((_month - 14) / 12) * 12)) / 12
- (3 * ((_year + 4900 + (_month - 14) / 12) / 100)) / 4 - OFFSET19700101;
_days = uint256(__days);
}
// ------------------------------------------------------------------------
// Calculate year/month/day from the number of days since 1970/01/01 using
// the date conversion algorithm from
// http://aa.usno.navy.mil/faq/docs/JD_Formula.php
// and adding the offset 2440588 so that 1970/01/01 is day 0
//
// int L = days + 68569 + offset
// int N = 4 * L / 146097
// L = L - (146097 * N + 3) / 4
// year = 4000 * (L + 1) / 1461001
// L = L - 1461 * year / 4 + 31
// month = 80 * L / 2447
// dd = L - 2447 * month / 80
// L = month / 11
// month = month + 2 - 12 * L
// year = 100 * (N - 49) + year + L
// ------------------------------------------------------------------------
function _daysToDate(uint256 _days) internal pure returns (uint256 year, uint256 month, uint256 day) {
unchecked {
int256 __days = int256(_days);
int256 L = __days + 68569 + OFFSET19700101;
int256 N = (4 * L) / 146097;
L = L - (146097 * N + 3) / 4;
int256 _year = (4000 * (L + 1)) / 1461001;
L = L - (1461 * _year) / 4 + 31;
int256 _month = (80 * L) / 2447;
int256 _day = L - (2447 * _month) / 80;
L = _month / 11;
_month = _month + 2 - 12 * L;
_year = 100 * (N - 49) + _year + L;
year = uint256(_year);
month = uint256(_month);
day = uint256(_day);
}
}
function timestampFromDate(uint256 year, uint256 month, uint256 day) internal pure returns (uint256 timestamp) {
timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY;
}
function timestampFromDateTime(
uint256 year,
uint256 month,
uint256 day,
uint256 hour,
uint256 minute,
uint256 second
)
internal
pure
returns (uint256 timestamp)
{
timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + hour * SECONDS_PER_HOUR
+ minute * SECONDS_PER_MINUTE + second;
}
function timestampToDate(uint256 timestamp) internal pure returns (uint256 year, uint256 month, uint256 day) {
unchecked {
(year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);
}
}
function timestampToDateTime(uint256 timestamp)
internal
pure
returns (uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute, uint256 second)
{
unchecked {
(year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY);
uint256 secs = timestamp % SECONDS_PER_DAY;
hour = secs / SECONDS_PER_HOUR;
secs = secs % SECONDS_PER_HOUR;
minute = secs / SECONDS_PER_MINUTE;
second = secs % SECONDS_PER_MINUTE;
}
}
function isValidDate(uint256 year, uint256 month, uint256 day) internal pure returns (bool valid) {
if (year >= 1970 && month > 0 && month <= 12) {
uint256 daysInMonth = _getDaysInMonth(year, month);
if (day > 0 && day <= daysInMonth) {
valid = true;
}
}
}
function isValidDateTime(uint256 year, uint256 month, uint256 day, uint256 hour, uint256 minute, uint256 second)
internal
pure
returns (bool valid)
{
if (isValidDate(year, month, day)) {
if (hour < 24 && minute < 60 && second < 60) {
valid = true;
}
}
}
function isLeapYear(uint256 timestamp) internal pure returns (bool leapYear) {
(uint256 year,,) = _daysToDate(timestamp / SECONDS_PER_DAY);
leapYear = _isLeapYear(year);
}
function _isLeapYear(uint256 year) internal pure returns (bool leapYear) {
leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}
function isWeekDay(uint256 timestamp) internal pure returns (bool weekDay) {
weekDay = getDayOfWeek(timestamp) <= DOW_FRI;
}
function isWeekEnd(uint256 timestamp) internal pure returns (bool weekEnd) {
weekEnd = getDayOfWeek(timestamp) >= DOW_SAT;
}
function getDaysInMonth(uint256 timestamp) internal pure returns (uint256 daysInMonth) {
(uint256 year, uint256 month,) = _daysToDate(timestamp / SECONDS_PER_DAY);
daysInMonth = _getDaysInMonth(year, month);
}
function _getDaysInMonth(uint256 year, uint256 month) internal pure returns (uint256 daysInMonth) {
if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) {
daysInMonth = 31;
} else if (month != 2) {
daysInMonth = 30;
} else {
daysInMonth = _isLeapYear(year) ? 29 : 28;
}
}
// 1 = Monday, 7 = Sunday
function getDayOfWeek(uint256 timestamp) internal pure returns (uint256 dayOfWeek) {
uint256 _days = timestamp / SECONDS_PER_DAY;
dayOfWeek = ((_days + 3) % 7) + 1;
}
function getYear(uint256 timestamp) internal pure returns (uint256 year) {
(year,,) = _daysToDate(timestamp / SECONDS_PER_DAY);
}
function getMonth(uint256 timestamp) internal pure returns (uint256 month) {
(, month,) = _daysToDate(timestamp / SECONDS_PER_DAY);
}
function getDay(uint256 timestamp) internal pure returns (uint256 day) {
(,, day) = _daysToDate(timestamp / SECONDS_PER_DAY);
}
function getHour(uint256 timestamp) internal pure returns (uint256 hour) {
uint256 secs = timestamp % SECONDS_PER_DAY;
hour = secs / SECONDS_PER_HOUR;
}
function getMinute(uint256 timestamp) internal pure returns (uint256 minute) {
uint256 secs = timestamp % SECONDS_PER_HOUR;
minute = secs / SECONDS_PER_MINUTE;
}
function getSecond(uint256 timestamp) internal pure returns (uint256 second) {
second = timestamp % SECONDS_PER_MINUTE;
}
function addYears(uint256 timestamp, uint256 _years) internal pure returns (uint256 newTimestamp) {
(uint256 year, uint256 month, uint256 day) = _daysToDate(timestamp / SECONDS_PER_DAY);
year += _years;
uint256 daysInMonth = _getDaysInMonth(year, month);
if (day > daysInMonth) {
day = daysInMonth;
}
newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + (timestamp % SECONDS_PER_DAY);
require(newTimestamp >= timestamp);
}
function addMonths(uint256 timestamp, uint256 _months) internal pure returns (uint256 newTimestamp) {
(uint256 year, uint256 month, uint256 day) = _daysToDate(timestamp / SECONDS_PER_DAY);
month += _months;
year += (month - 1) / 12;
month = ((month - 1) % 12) + 1;
uint256 daysInMonth = _getDaysInMonth(year, month);
if (day > daysInMonth) {
day = daysInMonth;
}
newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + (timestamp % SECONDS_PER_DAY);
require(newTimestamp >= timestamp);
}
function addDays(uint256 timestamp, uint256 _days) internal pure returns (uint256 newTimestamp) {
newTimestamp = timestamp + _days * SECONDS_PER_DAY;
require(newTimestamp >= timestamp);
}
function addHours(uint256 timestamp, uint256 _hours) internal pure returns (uint256 newTimestamp) {
newTimestamp = timestamp + _hours * SECONDS_PER_HOUR;
require(newTimestamp >= timestamp);
}
function addMinutes(uint256 timestamp, uint256 _minutes) internal pure returns (uint256 newTimestamp) {
newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE;
require(newTimestamp >= timestamp);
}
function addSeconds(uint256 timestamp, uint256 _seconds) internal pure returns (uint256 newTimestamp) {
newTimestamp = timestamp + _seconds;
require(newTimestamp >= timestamp);
}
function subYears(uint256 timestamp, uint256 _years) internal pure returns (uint256 newTimestamp) {
(uint256 year, uint256 month, uint256 day) = _daysToDate(timestamp / SECONDS_PER_DAY);
year -= _years;
uint256 daysInMonth = _getDaysInMonth(year, month);
if (day > daysInMonth) {
day = daysInMonth;
}
newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + (timestamp % SECONDS_PER_DAY);
require(newTimestamp <= timestamp);
}
function subMonths(uint256 timestamp, uint256 _months) internal pure returns (uint256 newTimestamp) {
(uint256 year, uint256 month, uint256 day) = _daysToDate(timestamp / SECONDS_PER_DAY);
uint256 yearMonth = year * 12 + (month - 1) - _months;
year = yearMonth / 12;
month = (yearMonth % 12) + 1;
uint256 daysInMonth = _getDaysInMonth(year, month);
if (day > daysInMonth) {
day = daysInMonth;
}
newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + (timestamp % SECONDS_PER_DAY);
require(newTimestamp <= timestamp);
}
function subDays(uint256 timestamp, uint256 _days) internal pure returns (uint256 newTimestamp) {
newTimestamp = timestamp - _days * SECONDS_PER_DAY;
require(newTimestamp <= timestamp);
}
function subHours(uint256 timestamp, uint256 _hours) internal pure returns (uint256 newTimestamp) {
newTimestamp = timestamp - _hours * SECONDS_PER_HOUR;
require(newTimestamp <= timestamp);
}
function subMinutes(uint256 timestamp, uint256 _minutes) internal pure returns (uint256 newTimestamp) {
newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE;
require(newTimestamp <= timestamp);
}
function subSeconds(uint256 timestamp, uint256 _seconds) internal pure returns (uint256 newTimestamp) {
newTimestamp = timestamp - _seconds;
require(newTimestamp <= timestamp);
}
function diffYears(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _years) {
require(fromTimestamp <= toTimestamp);
(uint256 fromYear,,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY);
(uint256 toYear,,) = _daysToDate(toTimestamp / SECONDS_PER_DAY);
_years = toYear - fromYear;
}
function diffMonths(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _months) {
require(fromTimestamp <= toTimestamp);
(uint256 fromYear, uint256 fromMonth,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY);
(uint256 toYear, uint256 toMonth,) = _daysToDate(toTimestamp / SECONDS_PER_DAY);
_months = toYear * 12 + toMonth - fromYear * 12 - fromMonth;
}
function diffDays(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _days) {
require(fromTimestamp <= toTimestamp);
_days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY;
}
function diffHours(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _hours) {
require(fromTimestamp <= toTimestamp);
_hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR;
}
function diffMinutes(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _minutes) {
require(fromTimestamp <= toTimestamp);
_minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE;
}
function diffSeconds(uint256 fromTimestamp, uint256 toTimestamp) internal pure returns (uint256 _seconds) {
require(fromTimestamp <= toTimestamp);
_seconds = toTimestamp - fromTimestamp;
}
}// 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.8.0;
import '@mimic-fi/v3-tasks/contracts/interfaces/ITask.sol';
import './IProtocolFeeWithdrawer.sol';
/**
* @title Balancer claimer interface
*/
interface IBalancerClaimer is ITask {
/**
* @dev The token is zero
*/
error TaskTokenZero();
/**
* @dev The amount is zero
*/
error TaskAmountZero();
/**
* @dev The protocol fee withdrawer is zero
*/
error TaskProtocolFeeWithdrawerZero();
/**
* @dev The protocol fees collector is zero
*/
error TaskProtocolFeesCollectorZero();
/**
* @dev The previous balance connector is not zero
*/
error TaskPreviousConnectorNotZero(bytes32 id);
/**
* @dev Emitted every time the protocol fee withdrawer is set
*/
event ProtocolFeeWithdrawerSet(address indexed protocolFeeWithdrawer);
/**
* @dev Emitted every time the protocol fees collector is set
*/
event ProtocolFeesCollectorSet(address indexed protocolFeesCollector);
/**
* @dev Tells the protocol fee withdrawer address
*/
function protocolFeeWithdrawer() external view returns (address);
/**
* @dev Tells the protocol fee collector address
*/
function protocolFeesCollector() external view returns (address);
/**
* @dev Sets the protocol fee withdrawer address. Sender must be authorized.
* @param newProtocolFeeWithdrawer Address of the protocol fee withdrawer to be set
*/
function setProtocolFeeWithdrawer(address newProtocolFeeWithdrawer) external;
/**
* @dev Sets the protocol fees collector address. Sender must be authorized.
* @param newProtocolFeesCollector Address of the protocol fees collector to be set
*/
function setProtocolFeesCollector(address newProtocolFeesCollector) external;
/**
* @dev Executes the Balancer claimer task
*/
function call(address token, uint256 amount) 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.8.0;
import '@mimic-fi/v3-tasks/contracts/interfaces/ITask.sol';
import '@mimic-fi/v3-smart-vault/contracts/interfaces/ISmartVault.sol';
/**
* @title Balancer claimer interface
*/
interface IMigrationClaimer is ITask {
/**
* @dev The token is zero
*/
error TaskTokenZero();
/**
* @dev The amount is zero
*/
error TaskAmountZero();
/**
* @dev The source smart vault is zero
*/
error TaskSourceSmartVaultZero();
/**
* @dev The previous balance connector is not zero
*/
error TaskPreviousConnectorNotZero(bytes32 id);
/**
* @dev Emitted every time the source smart vault is set
*/
event SourceSmartVaultSet(address indexed sourceSmartVault);
/**
* @dev Tells the source smart vault address
*/
function sourceSmartVault() external view returns (address);
/**
* @dev Sets the source smart vault address. Sender must be authorized.
* @param newSourceSmartVault Address of the source smart vault to be set
*/
function setSourceSmartVault(address newSourceSmartVault) external;
/**
* @dev Executes the Migration claimer task
*/
function call(address token, uint256 amount) 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.8.0;
interface IOldSmartVault {
/**
* @dev Withdraw tokens to an external account
* @param token Address of the token to be withdrawn
* @param amount Amount of tokens to withdraw
* @param recipient Address where the tokens will be transferred to
* @param data Extra data that may enable or not different behaviors depending on the implementation
* @return withdrawn Amount of tokens transferred to the recipient address
*/
function withdraw(address token, uint256 amount, address recipient, bytes memory data)
external
returns (uint256 withdrawn);
}// 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.8.0;
interface IProtocolFeeWithdrawer {
function withdrawCollectedFees(address[] calldata tokens, uint256[] calldata amounts, address recipient) 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.8.0;
interface ISmartVaultV2 {
function withdraw(address token, uint256 amount, address recipient, bytes memory data)
external
returns (uint256 withdrawn);
}// 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.8.0;
import '@mimic-fi/v3-tasks/contracts/interfaces/ITask.sol';
/**
* @title V2 Smart Vault Migrator interface
*/
interface IV2SmartVaultMigrator is ITask {
/**
* @dev The token is zero
*/
error TaskTokenZero();
/**
* @dev The amount is zero
*/
error TaskAmountZero();
/**
* @dev The source smart vault is zero
*/
error TaskSourceSmartVaultZero();
/**
* @dev The previous balance connector is not zero
*/
error TaskPreviousConnectorNotZero(bytes32 id);
/**
* @dev Emitted every time the source smart vault is set
*/
event SourceSmartVaultSet(address indexed sourceSmartVault);
/**
* @dev Tells the source smart vault address
*/
function sourceSmartVault() external view returns (address);
/**
* @dev Sets the source smart vault address. Sender must be authorized.
* @param newSourceSmartVault Address of the source smart vault to be set
*/
function setSourceSmartVault(address newSourceSmartVault) external;
/**
* @dev Executes the v2 smart vault migrator task
*/
function call(address token, uint256 amount) 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.8.0;
import '@mimic-fi/v3-tasks/contracts/Task.sol';
import '@mimic-fi/v3-helpers/contracts/utils/ERC20Helpers.sol';
import '@mimic-fi/v3-smart-vault/contracts/interfaces/ISmartVault.sol';
import './interfaces/IMigrationClaimer.sol';
import './interfaces/IOldSmartVault.sol';
/**
* @title Balancer claimer
* @dev Task used to claim tokens from Balancer's Source smart vault
*/
contract MigrationClaimer is IMigrationClaimer, Task {
// Execution type for relayers
bytes32 public constant override EXECUTION_TYPE = keccak256('MIGRATION_CLAIMER');
// Source smart vault address
address public override sourceSmartVault;
/**
* @dev Initializes the balancer claimer
* @param config Task config
* @param smartVault Source smart vault address
*/
function initializeMigrationClaimer(TaskConfig memory config, address smartVault) external virtual initializer {
__MigrationClaimer_init(config, smartVault);
}
/**
* @dev Initializes the balancer claimer. It does call upper contracts initializers.
* @param config Task config
* @param smartVault Source smart vault address
*/
function __MigrationClaimer_init(TaskConfig memory config, address smartVault) internal onlyInitializing {
__Task_init(config);
__MigrationClaimer_init_unchained(config, smartVault);
}
/**
* @dev Initializes the balancer claimer. It does not call upper contracts initializers.
* @param smartVault Source smart vault address
*/
function __MigrationClaimer_init_unchained(TaskConfig memory, address smartVault) internal onlyInitializing {
_setSourceSmartVault(smartVault);
}
/**
* @dev Tells the address from where the token amounts to execute this task are fetched
*/
function getTokensSource() external view virtual override(IBaseTask, BaseTask) returns (address) {
return sourceSmartVault;
}
/**
* @dev Tells the token balance in the source smart vault
* @param token Address of the token being queried
*/
function getTaskAmount(address token) public view virtual override(IBaseTask, BaseTask) returns (uint256) {
return ERC20Helpers.balanceOf(token, sourceSmartVault);
}
/**
* @dev Sets the Source smart vault address. Sender must be authorized.
* @param newSourceSmartVault Address of the Source smart vault to be set
*/
function setSourceSmartVault(address newSourceSmartVault) external override authP(authParams(newSourceSmartVault)) {
_setSourceSmartVault(newSourceSmartVault);
}
/**
* @dev Executes the Balancer claimer task
*/
function call(address token, uint256 amount) external override authP(authParams(token, amount)) {
if (amount == 0) amount = getTaskAmount(token);
_beforeMigrationClaimer(token, amount);
// solhint-disable-next-line avoid-low-level-calls
ISmartVault(smartVault).call(sourceSmartVault, _buildMigrationClaimerData(token, amount), 0);
_afterMigrationClaimer(token, amount);
}
/**
* @dev Builds Source smart vault calldata
*/
function _buildMigrationClaimerData(address token, uint256 amount) internal view returns (bytes memory) {
return abi.encodeWithSelector(IOldSmartVault.withdraw.selector, token, amount, smartVault, '0x');
}
/**
* @dev Before balancer claimer task hook
*/
function _beforeMigrationClaimer(address token, uint256 amount) internal {
_beforeTask(token, amount);
if (token == address(0)) revert TaskTokenZero();
if (amount == 0) revert TaskAmountZero();
}
/**
* @dev After balancer claimer task hook
*/
function _afterMigrationClaimer(address token, uint256 amount) internal {
_increaseBalanceConnector(token, amount);
_afterTask(token, amount);
}
/**
* @dev Sets the Source smart vault address
* @param newSourceSmartVault Address of the Source smart vault to be set
*/
function _setSourceSmartVault(address newSourceSmartVault) internal {
if (newSourceSmartVault == address(0)) revert TaskSourceSmartVaultZero();
sourceSmartVault = newSourceSmartVault;
emit SourceSmartVaultSet(newSourceSmartVault);
}
/**
* @dev Sets the balance connectors. Previous balance connector must be unset.
* @param previous Balance connector id of the previous task in the workflow
* @param next Balance connector id of the next task in the workflow
*/
function _setBalanceConnectors(bytes32 previous, bytes32 next) internal virtual override {
if (previous != bytes32(0)) revert TaskPreviousConnectorNotZero(previous);
super._setBalanceConnectors(previous, next);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import '../interfaces/IProtocolFeeWithdrawer.sol';
contract ProtocolFeeWithdrawerMock is IProtocolFeeWithdrawer {
using SafeERC20 for IERC20;
// Protocol fees collector address
address public protocolFeesCollector;
constructor(address _protocolFeesCollector) {
protocolFeesCollector = _protocolFeesCollector;
}
function withdrawCollectedFees(address[] calldata tokens, uint256[] calldata amounts, address recipient)
external
override
{
require(tokens.length == amounts.length, 'WITHDRAWER_INVALID_INPUT_LEN');
for (uint256 i = 0; i < tokens.length; i++) {
require(IERC20(tokens[i]).balanceOf(protocolFeesCollector) >= amounts[i], 'INVALID_WITHDRAWER_BALANCE');
IERC20(tokens[i]).safeTransferFrom(protocolFeesCollector, recipient, amounts[i]);
}
}
}// 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.8.0;
import '@mimic-fi/v3-helpers/contracts/utils/ERC20Helpers.sol';
import '../interfaces/ISmartVaultV2.sol';
contract SmartVaultV2Mock is ISmartVaultV2 {
receive() external payable {
// solhint-disable-previous-line no-empty-blocks
}
function withdraw(address token, uint256 amount, address recipient, bytes memory)
external
returns (uint256 withdrawn)
{
ERC20Helpers.transfer(token, recipient, amount);
return amount;
}
}// 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.8.17;
import '@mimic-fi/v3-helpers/contracts/utils/ERC20Helpers.sol';
import '@mimic-fi/v3-smart-vault/contracts/interfaces/ISmartVault.sol';
import '@mimic-fi/v3-tasks/contracts/Task.sol';
import './interfaces/IV2SmartVaultMigrator.sol';
import './interfaces/ISmartVaultV2.sol';
/**
* @title V2 Smart Vault Migrator
* @dev Task used to withdraw tokens from BT's V2 smart vault
*/
contract V2SmartVaultMigrator is IV2SmartVaultMigrator, Task {
// Execution type for relayers
bytes32 public constant override EXECUTION_TYPE = keccak256('V2_SMART_VAULT_MIGRATOR');
// Reference to the source smart vault
address public override sourceSmartVault;
/**
* @dev Initializes the v2 smart vault migrator
* @param config Task config
* @param source Address of the source smart vault
*/
function initializeV2SmartVaultMigrator(TaskConfig memory config, address source) external initializer {
__V2SmartVaultMigrator_init(config, source);
}
/**
* @dev Initializes the v2 smart vault migrator. It does call upper contracts initializers.
* @param config Task config
* @param source Address of the source smart vault
*/
function __V2SmartVaultMigrator_init(TaskConfig memory config, address source) internal onlyInitializing {
__Task_init(config);
__V2SmartVaultMigrator_init_unchained(config, source);
}
/**
* @dev Initializes the v2 smart vault migrator. It does not call upper contracts initializers.
* @param source Address of the source smart vault
*/
function __V2SmartVaultMigrator_init_unchained(TaskConfig memory, address source) internal onlyInitializing {
_setSourceSmartVault(source);
}
/**
* @dev Tells the address from where the token amounts to execute this task are fetched
*/
function getTokensSource() public view override(IBaseTask, BaseTask) returns (address) {
return sourceSmartVault;
}
/**
* @dev Tells the token balance in the source smart vault
* @param token Address of the token being queried
*/
function getTaskAmount(address token) public view override(IBaseTask, BaseTask) returns (uint256) {
return ERC20Helpers.balanceOf(token, getTokensSource());
}
/**
* @dev Sets the source smart vault address. Sender must be authorized.
* @param newSourceSmartVault Address of the source smart vault to be set
*/
function setSourceSmartVault(address newSourceSmartVault) external override authP(authParams(newSourceSmartVault)) {
_setSourceSmartVault(newSourceSmartVault);
}
/**
* @dev Executes the v2 smart vault migrator task
*/
function call(address token, uint256 amount) external override authP(authParams(token, amount)) {
if (amount == 0) amount = getTaskAmount(token);
_beforeV2SmartVaultMigrator(token, amount);
bytes memory data = abi.encodeWithSelector(
ISmartVaultV2.withdraw.selector,
token,
amount,
smartVault,
new bytes(0)
);
// solhint-disable-next-line avoid-low-level-calls
ISmartVault(smartVault).call(sourceSmartVault, data, 0);
_afterV2SmartVaultMigrator(token, amount);
}
/**
* @dev Before v2 smart vault migrator task hook
*/
function _beforeV2SmartVaultMigrator(address token, uint256 amount) internal {
_beforeTask(token, amount);
if (token == address(0)) revert TaskTokenZero();
if (amount == 0) revert TaskAmountZero();
}
/**
* @dev After v2 smart vault migrator task hook
*/
function _afterV2SmartVaultMigrator(address token, uint256 amount) internal {
_increaseBalanceConnector(token, amount);
_afterTask(token, amount);
}
/**
* @dev Sets the source smart vault address
* @param newSourceSmartVault Address of the source smart vault to be set
*/
function _setSourceSmartVault(address newSourceSmartVault) internal {
if (newSourceSmartVault == address(0)) revert TaskSourceSmartVaultZero();
sourceSmartVault = newSourceSmartVault;
emit SourceSmartVaultSet(newSourceSmartVault);
}
/**
* @dev Sets the balance connectors. Previous balance connector must be unset.
* @param previous Balance connector id of the previous task in the workflow
* @param next Balance connector id of the next task in the workflow
*/
function _setBalanceConnectors(bytes32 previous, bytes32 next) internal override {
if (previous != bytes32(0)) revert TaskPreviousConnectorNotZero(previous);
super._setBalanceConnectors(previous, next);
}
}{
"optimizer": {
"enabled": true,
"runs": 10000
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"who","type":"address"},{"internalType":"bytes4","name":"what","type":"bytes4"},{"internalType":"uint256[]","name":"how","type":"uint256[]"}],"name":"AuthSenderNotAllowed","type":"error"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"aInflated","type":"uint256"}],"name":"FixedPointDivInternal","type":"error"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"}],"name":"FixedPointMulOverflow","type":"error"},{"inputs":[],"name":"FixedPointZeroDivision","type":"error"},{"inputs":[],"name":"TaskAcceptanceInputLengthMismatch","type":"error"},{"inputs":[],"name":"TaskAcceptanceTokenZero","type":"error"},{"inputs":[],"name":"TaskAmountZero","type":"error"},{"inputs":[],"name":"TaskGasNotInitialized","type":"error"},{"inputs":[{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"gasPriceLimit","type":"uint256"}],"name":"TaskGasPriceLimitExceeded","type":"error"},{"inputs":[{"internalType":"uint8","name":"mode","type":"uint8"},{"internalType":"uint256","name":"date","type":"uint256"}],"name":"TaskInvalidAllowedDate","type":"error"},{"inputs":[{"internalType":"uint8","name":"mode","type":"uint8"},{"internalType":"uint256","name":"window","type":"uint256"}],"name":"TaskInvalidAllowedWindow","type":"error"},{"inputs":[{"internalType":"uint8","name":"mode","type":"uint8"},{"internalType":"uint256","name":"frequency","type":"uint256"}],"name":"TaskInvalidFrequency","type":"error"},{"inputs":[{"internalType":"uint8","name":"mode","type":"uint8"}],"name":"TaskInvalidFrequencyMode","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"TaskInvalidThresholdInput","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"period","type":"uint256"}],"name":"TaskInvalidVolumeLimitInput","type":"error"},{"inputs":[],"name":"TaskPaused","type":"error"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"TaskPreviousConnectorNotZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"priorityFee","type":"uint256"},{"internalType":"uint256","name":"priorityFeeLimit","type":"uint256"}],"name":"TaskPriorityFeeLimitExceeded","type":"error"},{"inputs":[],"name":"TaskProtocolFeeWithdrawerZero","type":"error"},{"inputs":[],"name":"TaskProtocolFeesCollectorZero","type":"error"},{"inputs":[{"internalType":"bytes32","name":"connectorId","type":"bytes32"}],"name":"TaskSameBalanceConnectors","type":"error"},{"inputs":[{"internalType":"address","name":"smartVault","type":"address"}],"name":"TaskSmartVaultPriceOracleNotSet","type":"error"},{"inputs":[],"name":"TaskThresholdTokenZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentTimestamp","type":"uint256"},{"internalType":"uint256","name":"expiration","type":"uint256"}],"name":"TaskTimeLockActive","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"TaskTokenNotAllowed","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"TaskTokenThresholdNotMet","type":"error"},{"inputs":[],"name":"TaskTokenZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"txCost","type":"uint256"},{"internalType":"uint256","name":"txCostLimit","type":"uint256"}],"name":"TaskTxCostLimitExceeded","type":"error"},{"inputs":[],"name":"TaskTxCostLimitPctAboveOne","type":"error"},{"inputs":[{"internalType":"uint256","name":"txCostPct","type":"uint256"},{"internalType":"uint256","name":"txCostLimitPct","type":"uint256"}],"name":"TaskTxCostLimitPctExceeded","type":"error"},{"inputs":[],"name":"TaskUnpaused","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint256","name":"volume","type":"uint256"}],"name":"TaskVolumeLimitExceeded","type":"error"},{"inputs":[],"name":"TaskVolumeLimitTokenZero","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"previous","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"next","type":"bytes32"}],"name":"BalanceConnectorsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"thresholdToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"min","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"max","type":"uint256"}],"name":"CustomTokenThresholdSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"limitToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"period","type":"uint256"}],"name":"CustomVolumeLimitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"min","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"max","type":"uint256"}],"name":"DefaultTokenThresholdSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"limitToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"period","type":"uint256"}],"name":"DefaultVolumeLimitSet","type":"event"},{"anonymous":false,"inputs":[],"name":"Executed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"gasPriceLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"priorityFeeLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"txCostLimit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"txCostLimitPct","type":"uint256"}],"name":"GasLimitsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"protocolFeeWithdrawer","type":"address"}],"name":"ProtocolFeeWithdrawerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"protocolFeesCollector","type":"address"}],"name":"ProtocolFeesCollectorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"allowedAt","type":"uint256"}],"name":"TimeLockAllowedAtSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"mode","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"frequency","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"allowedAt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"window","type":"uint256"}],"name":"TimeLockSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"bool","name":"added","type":"bool"}],"name":"TokensAcceptanceListSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum ITokenIndexedTask.TokensAcceptanceType","name":"acceptanceType","type":"uint8"}],"name":"TokensAcceptanceTypeSet","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpaused","type":"event"},{"inputs":[],"name":"EXECUTION_TYPE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authorizer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"call","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"customTokenThreshold","outputs":[{"internalType":"address","name":"thresholdToken","type":"address"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"customVolumeLimit","outputs":[{"internalType":"address","name":"limitToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"accrued","type":"uint256"},{"internalType":"uint256","name":"period","type":"uint256"},{"internalType":"uint256","name":"nextResetTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultTokenThreshold","outputs":[{"internalType":"address","name":"thresholdToken","type":"address"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultVolumeLimit","outputs":[{"internalType":"address","name":"limitToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"accrued","type":"uint256"},{"internalType":"uint256","name":"period","type":"uint256"},{"internalType":"uint256","name":"nextResetTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBalanceConnectors","outputs":[{"internalType":"bytes32","name":"previous","type":"bytes32"},{"internalType":"bytes32","name":"next","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGasLimits","outputs":[{"internalType":"uint256","name":"gasPriceLimit","type":"uint256"},{"internalType":"uint256","name":"priorityFeeLimit","type":"uint256"},{"internalType":"uint256","name":"txCostLimit","type":"uint256"},{"internalType":"uint256","name":"txCostLimitPct","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getTaskAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTimeLock","outputs":[{"internalType":"uint8","name":"mode","type":"uint8"},{"internalType":"uint256","name":"frequency","type":"uint256"},{"internalType":"uint256","name":"allowedAt","type":"uint256"},{"internalType":"uint256","name":"window","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getTokenThreshold","outputs":[{"internalType":"address","name":"thresholdToken","type":"address"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTokensSource","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getVolumeLimit","outputs":[{"internalType":"address","name":"limitToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"accrued","type":"uint256"},{"internalType":"uint256","name":"period","type":"uint256"},{"internalType":"uint256","name":"nextResetTime","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"smartVault","type":"address"},{"internalType":"bytes32","name":"previousBalanceConnectorId","type":"bytes32"},{"internalType":"bytes32","name":"nextBalanceConnectorId","type":"bytes32"}],"internalType":"struct BaseTask.BaseConfig","name":"baseConfig","type":"tuple"},{"components":[{"internalType":"uint256","name":"gasPriceLimit","type":"uint256"},{"internalType":"uint256","name":"priorityFeeLimit","type":"uint256"},{"internalType":"uint256","name":"txCostLimit","type":"uint256"},{"internalType":"uint256","name":"txCostLimitPct","type":"uint256"}],"internalType":"struct GasLimitedTask.GasLimitConfig","name":"gasLimitConfig","type":"tuple"},{"components":[{"internalType":"uint8","name":"mode","type":"uint8"},{"internalType":"uint256","name":"frequency","type":"uint256"},{"internalType":"uint256","name":"allowedAt","type":"uint256"},{"internalType":"uint256","name":"window","type":"uint256"}],"internalType":"struct TimeLockedTask.TimeLockConfig","name":"timeLockConfig","type":"tuple"},{"components":[{"internalType":"enum ITokenIndexedTask.TokensAcceptanceType","name":"acceptanceType","type":"uint8"},{"internalType":"address[]","name":"tokens","type":"address[]"}],"internalType":"struct TokenIndexedTask.TokenIndexConfig","name":"tokenIndexConfig","type":"tuple"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"internalType":"struct TokenThresholdTask.Threshold","name":"defaultThreshold","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"internalType":"struct TokenThresholdTask.Threshold","name":"threshold","type":"tuple"}],"internalType":"struct TokenThresholdTask.CustomThresholdConfig[]","name":"customThresholdConfigs","type":"tuple[]"}],"internalType":"struct TokenThresholdTask.TokenThresholdConfig","name":"tokenThresholdConfig","type":"tuple"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"period","type":"uint256"}],"internalType":"struct VolumeLimitedTask.VolumeLimitParams","name":"defaultVolumeLimit","type":"tuple"},{"components":[{"internalType":"address","name":"token","type":"address"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"period","type":"uint256"}],"internalType":"struct VolumeLimitedTask.VolumeLimitParams","name":"volumeLimit","type":"tuple"}],"internalType":"struct VolumeLimitedTask.CustomVolumeLimitConfig[]","name":"customVolumeLimitConfigs","type":"tuple[]"}],"internalType":"struct VolumeLimitedTask.VolumeLimitConfig","name":"volumeLimitConfig","type":"tuple"}],"internalType":"struct Task.TaskConfig","name":"config","type":"tuple"},{"internalType":"address","name":"withdrawer","type":"address"},{"internalType":"address","name":"collector","type":"address"}],"name":"initializeBalancerClaimer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"isTokenAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"protocolFeeWithdrawer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolFeesCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"previous","type":"bytes32"},{"internalType":"bytes32","name":"next","type":"bytes32"}],"name":"setBalanceConnectors","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"thresholdToken","type":"address"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"setCustomTokenThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"limitToken","type":"address"},{"internalType":"uint256","name":"limitAmount","type":"uint256"},{"internalType":"uint256","name":"limitPeriod","type":"uint256"}],"name":"setCustomVolumeLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"thresholdToken","type":"address"},{"internalType":"uint256","name":"min","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"setDefaultTokenThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"limitToken","type":"address"},{"internalType":"uint256","name":"limitAmount","type":"uint256"},{"internalType":"uint256","name":"limitPeriod","type":"uint256"}],"name":"setDefaultVolumeLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newGasPriceLimit","type":"uint256"},{"internalType":"uint256","name":"newPriorityFeeLimit","type":"uint256"},{"internalType":"uint256","name":"newTxCostLimit","type":"uint256"},{"internalType":"uint256","name":"newTxCostLimitPct","type":"uint256"}],"name":"setGasLimits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newProtocolFeeWithdrawer","type":"address"}],"name":"setProtocolFeeWithdrawer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newProtocolFeesCollector","type":"address"}],"name":"setProtocolFeesCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"mode","type":"uint8"},{"internalType":"uint256","name":"frequency","type":"uint256"},{"internalType":"uint256","name":"allowedAt","type":"uint256"},{"internalType":"uint256","name":"window","type":"uint256"}],"name":"setTimeLock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"bool[]","name":"added","type":"bool[]"}],"name":"setTokensAcceptanceList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum ITokenIndexedTask.TokensAcceptanceType","name":"newTokensAcceptanceType","type":"uint8"}],"name":"setTokensAcceptanceType","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"smartVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokensAcceptanceType","outputs":[{"internalType":"enum ITokenIndexedTask.TokensAcceptanceType","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60806040523480156200001157600080fd5b506200001c62000022565b620000e4565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161015620000e2576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b61524b80620000f46000396000f3fe608060405234801561001057600080fd5b50600436106102265760003560e01c80636b1239191161012a578063b187bd26116100bd578063d45a76cf1161008c578063e6b5be9811610071578063e6b5be9814610648578063e97b80711461065b578063f9eaee0d1461066e57600080fd5b8063d45a76cf14610622578063db20de821461063557600080fd5b8063b187bd26146105c8578063c267621e146105e5578063d09edf31146105f6578063d3feb6021461060f57600080fd5b806390333ba8116100f957806390333ba814610515578063a0c3774f14610528578063a33741771461053b578063a5900c4d1461056e57600080fd5b80636b123919146104d45780637125590a146104e75780637cbd3a56146104fa5780638456cb591461050d57600080fd5b80633f4ba83a116101bd5780634fd49efd1161018c5780635670e2ce116101715780635670e2ce146104415780635ea54eee1461045c5780636aacaad81461048857600080fd5b80634fd49efd146103de57806351a424b11461040957600080fd5b80633f4ba83a14610374578063423a4b401461037c57806342d4693e1461038f5780634a45a3a8146103a957600080fd5b8063221a8c68116101f9578063221a8c68146102975780632384c32d1461033b57806330eae5721461034e5780633bd9ef281461036157600080fd5b80630ef917ed1461022b5780630fe105e814610240578063119a5e96146102535780632197238414610284575b600080fd5b61023e6102393660046144a0565b610681565b005b61023e61024e3660046144ce565b6106c6565b61025b610717565b6040805160ff909516855260208501939093529183015260608201526080015b60405180910390f35b61023e61029236600461467c565b61074e565b6103096102a53660046144a0565b6001600160a01b039081166000908152601b6020908152604091829020825160a08101845281549094168085526001820154928501839052600282015493850184905260038201546060860181905260049092015460809095018590529491939091565b604080516001600160a01b0390961686526020860194909452928401919091526060830152608082015260a00161027b565b61023e610349366004614740565b610816565b61023e61035c366004614795565b61085d565b61023e61036f3660046147b0565b6108b2565b61023e61099e565b61023e61038a366004614740565b610a5b565b600f5461039c9060ff1681565b60405161027b919061480b565b6103d07f4f1a5aef466c18f2eefd210f80b744aa3b40590af293e84b695be7d70fd862b381565b60405190815260200161027b565b6001546103f1906001600160a01b031681565b6040516001600160a01b03909116815260200161027b565b61041c6104173660046144a0565b610aa2565b604080516001600160a01b03909416845260208401929092529082015260600161027b565b6002546003546040805192835260208301919091520161027b565b60065460075460085460095460408051948552602085019390935291830152606082015260800161027b565b6103096040805160a0810182526016546001600160a01b03168082526017546020830181905260185493830184905260195460608401819052601a546080909401849052919490939290565b601c546103f1906001600160a01b031681565b61023e6104f536600461484c565b610acb565b61023e610508366004614b5f565b610b0e565b61023e610c92565b61023e610523366004614c70565b610d53565b6103d06105363660046144a0565b610d98565b61041c604080516060810182526012546001600160a01b0316808252601354602083018190526014549290930182905292565b61041c61057c3660046144a0565b6001600160a01b03808216600090815260156020908152604091829020825160608101845281549094168085526001820154928501839052600290910154939092018390529093909250565b6004546105d59060ff1681565b604051901515815260200161027b565b601d546001600160a01b03166103f1565b6000546103f1906201000090046001600160a01b031681565b61023e61061d366004614c70565b610db8565b6103096106303660046144a0565b610dfd565b61023e6106433660046144a0565b610e6c565b61023e610656366004614ca5565b610ead565b601d546103f1906001600160a01b031681565b6105d561067c3660046144a0565b610ef4565b61068a81610f32565b6106b9336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b6106c282610f8d565b5050565b6106d58460ff1684848461102f565b610704336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b610710858585856110da565b5050505050565b600a5460009081908190819060ff166002811115610737576107376147dc565b600b54600c54600e54935093509350935090919293565b61077c336000357fffffffff0000000000000000000000000000000000000000000000000000000016611497565b80518251146107b7576040517f5d32021a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8251811015610811576107ff8382815181106107d8576107d8614cd7565b60200260200101518383815181106107f2576107f2614cd7565b60200260200101516114b3565b8061080981614d35565b9150506107ba565b505050565b6108228484848461155d565b610851336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b610710858585856115c6565b61087a816001811115610872576108726147dc565b60ff1661167f565b6108a9336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b6106c2826116c6565b6108bc8282611741565b6108eb336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b816000036108ff576108fc83610d98565b91505b61090983836117b0565b600154601c546001600160a01b0391821691634ae00041911661092c8686611834565b60006040518463ffffffff1660e01b815260040161094c93929190614dbd565b6000604051808303816000875af115801561096b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109939190810190614def565b506108118383611977565b6109cc336000357fffffffff0000000000000000000000000000000000000000000000000000000016611497565b60045460ff16610a08576040517f9e6558bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040517fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d1693390600090a1565b610a678484848461155d565b610a96336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b6107108585858561198b565b600080600080610ab185611a4b565b805160208201516040909201519097919650945092505050565b610ad58282611ad6565b610b04336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b6108118383611b30565b600054610100900460ff1615808015610b2e5750600054600160ff909116105b80610b485750303b158015610b48575060005460ff166001145b610bbf5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015610c1d57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b610c28848484611b75565b8015610c8c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a15b50505050565b610cc0336000357fffffffff0000000000000000000000000000000000000000000000000000000016611497565b60045460ff1615610cfd576040517fc0f2312800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e75290600090a1565b610d5e838383611bf4565b610d8d336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b610c8c848484611c86565b601d54600090610db29083906001600160a01b0316611cdc565b92915050565b610dc3838383611bf4565b610df2336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b610c8c848484611d9d565b600080600080600080610e0f87611df9565b6040805160a08101825282546001600160a01b031680825260018401546020830181905260028501549383018490526003850154606084018190526004909501546080909301839052909b909a5091985091965090945092505050565b610e7581610f32565b610ea4336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b6106c282611e2d565b610eb98484848461102f565b610ee8336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b61071085858585611ecf565b600080610f02601084611f6a565b90506001600f5460ff166001811115610f1d57610f1d6147dc565b14610f29578015610f2b565b805b9392505050565b6060610db2826001600160a01b031661167f565b610f51838383611f8c565b610811578282826040517f960c80da000000000000000000000000000000000000000000000000000000008152600401610bb693929190614ebe565b6001600160a01b038116610fcd576040517fdb6cf18100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601d80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f0c7d25a41bb896a3d198b4b4593a58cb7f37d8340b0b58bffa244676e2ef803a90600090a250565b60408051600480825260a0820190925260609160208201608080368337019050509050848160008151811061106657611066614cd7565b602002602001018181525050838160018151811061108657611086614cd7565b60200260200101818152505082816002815181106110a6576110a6614cd7565b60200260200101818152505081816003815181106110c6576110c6614cd7565b602002602001018181525050949350505050565b60ff84166111d65760008111806110f15750600082115b156111d1578260000361113c576040517fbea499cb00000000000000000000000000000000000000000000000000000000815260ff8516600482015260248101849052604401610bb6565b80158061114857508281115b1561118b576040517f9e12fccf00000000000000000000000000000000000000000000000000000000815260ff8516600482015260248101829052604401610bb6565b816000036111d1576040517fad0d7eb200000000000000000000000000000000000000000000000000000000815260ff8516600482015260248101839052604401610bb6565b6113ec565b8260000361121c576040517fbea499cb00000000000000000000000000000000000000000000000000000000815260ff8516600482015260248101849052604401610bb6565b80158061123457506112316224ea0084614f08565b81115b15611277576040517f9e12fccf00000000000000000000000000000000000000000000000000000000815260ff8516600482015260248101829052604401610bb6565b816000036112bd576040517fad0d7eb200000000000000000000000000000000000000000000000000000000815260ff8516600482015260248101839052604401610bb6565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60ff85160161133657601c6112f28361202a565b11156111d1576040517fad0d7eb200000000000000000000000000000000000000000000000000000000815260ff8516600482015260248101839052604401610bb6565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe60ff8516016113b55761136982612041565b6113728361202a565b146111d1576040517fad0d7eb200000000000000000000000000000000000000000000000000000000815260ff8516600482015260248101839052604401610bb6565b6040517f33a738bc00000000000000000000000000000000000000000000000000000000815260ff85166004820152602401610bb6565b8360ff166002811115611401576114016147dc565b600a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600183600281111561143b5761143b6147dc565b0217905550600b839055600c829055600e8190556040805160ff8616815260208101859052908101839052606081018290527f182fd6fa2a8560221614c1396dd4fcc78d26dfacf821a6afb61d25876057e41290608001610c83565b6040805160008152602081019091526106c29083908390610f46565b6001600160a01b0382166114f3576040517fc41a13ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061150857611503601083612064565b611513565b611513601083612079565b50816001600160a01b03167f6264362e9de26efefda321dfaeb4e4a9090deef40c5435fad8e9e2e306889a1c82604051611551911515815260200190565b60405180910390a25050565b60408051600480825260a0820190925260609160208201608080368337019050509050846001600160a01b03168160008151811061159d5761159d614cd7565b602002602001018181525050836001600160a01b03168160018151811061108657611086614cd7565b6001600160a01b038416611606576040517fe7ba3e4a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038416600090815260156020526040902061162a9084848461208e565b604080516001600160a01b03858116825260208201859052918101839052908516907ff099617c054d3a65e02a9c3b786f23cc03d5982bc7cfae84dff0408049cf17079060600160405180910390a250505050565b6040805160018082528183019092526060916020808301908036833701905050905081816000815181106116b5576116b5614cd7565b602002602001018181525050919050565b600f80548291907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660018381811115611702576117026147dc565b02179055507f216b6a9618d607ba436d0f2e17e9a83e70929adff805ac2385d67401360e551a81604051611736919061480b565b60405180910390a150565b6040805160028082526060808301845292602083019080368337019050509050826001600160a01b03168160008151811061177e5761177e614cd7565b602002602001018181525050818160018151811061179e5761179e614cd7565b60200260200101818152505092915050565b6117ba8282612176565b6001600160a01b0382166117fa576040517fc0e0f12200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806000036106c2576040517f1463acbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160018082528183019092526060916000919060208083019080368337019050509050838160008151811061186e5761186e614cd7565b6001600160a01b03929092166020928302919091019091015260408051600180825281830190925260009181602001602082028036833701905050905083816000815181106118bf576118bf614cd7565b60209081029190910101526001546040517f6daefab6000000000000000000000000000000000000000000000000000000009161190e91859185916001600160a01b0390911690602401614f1f565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529250505092915050565b61198182826121bc565b6106c2828261225b565b6001600160a01b0384166119cb576040517f1de0c9c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0384166000908152601b602052604090206119ef90848484612283565b826001600160a01b0316846001600160a01b03167f1b5c5e27ed5443e409bae85849d41d7bf12d5352e8fddb3728b6408f836e14488484604051611a3d929190918252602082015260400190565b60405180910390a350505050565b611a78604051806060016040528060006001600160a01b0316815260200160008152602001600081525090565b6001600160a01b038083166000908152601560205260409020805490911615611aa15780611aa4565b60125b6040805160608101825282546001600160a01b0316815260018301546020820152600290920154908201529392505050565b60408051600280825260608083018452926020830190803683370190505090508260001c81600081518110611b0d57611b0d614cd7565b6020026020010181815250508160001c8160018151811061179e5761179e614cd7565b8115611b6b576040517fade7e16800000000000000000000000000000000000000000000000000000000815260048101839052602401610bb6565b6106c282826123fa565b600054610100900460ff16611be05760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b611be98361247d565b610811838383612548565b60408051600380825260808201909252606091602082018380368337019050509050836001600160a01b031681600081518110611c3357611c33614cd7565b6020026020010181815250508281600181518110611c5357611c53614cd7565b6020026020010181815250508181600281518110611c7357611c73614cd7565b6020026020010181815250509392505050565b611c936016848484612283565b60408051838152602081018390526001600160a01b038516917f6324b5f18e615697a2b44f16d7a649deb0bbbc7cb09dad4c610306105730e7d9910160405180910390a2505050565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b03841603611d1357506001600160a01b03811631610db2565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa158015611d72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d969190614f90565b9050610db2565b611daa601284848461208e565b604080516001600160a01b0385168152602081018490529081018290527fa80953bdc344b2ebd0bcdd001a3418a8fd1b858bdecf12a4ba5a9366ad65d3459060600160405180910390a1505050565b6001600160a01b038082166000908152601b602052604081208054919290911615611e245780610f2b565b60169392505050565b6001600160a01b038116611e6d576040517f382928fe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601c80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517ffdbd8fd3124d4abea1394a5bf9d535d8b716508569491ceae023fc8f0221c73a90600090a250565b670de0b6b3a7640000811115611f11576040517fce57496100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068490556007839055600882905560098190556040805185815260208101859052908101839052606081018290527f746dc5eb53c5de07c40b06d428506d6982ea10c423ac2875abfc44038927d69190608001610c83565b6001600160a01b03811660009081526001830160205260408120541515610f2b565b600080546040517f28522895000000000000000000000000000000000000000000000000000000008152620100009091046001600160a01b031690632852289590611fe1908790309088908890600401614fa9565b602060405180830381865afa158015611ffe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120229190615007565b949350505050565b600061202261203c6201518084615053565b6125c5565b6000808061205561203c6201518086615053565b5091509150612022828261267f565b6000610f2b836001600160a01b038416612705565b6000610f2b836001600160a01b0384166127ff565b60006001600160a01b0384161580156120a5575082155b80156120af575081155b905060006001600160a01b038516158015906120d357508215806120d35750838310155b9050811580156120e1575080155b15612131576040517fca1f04830000000000000000000000000000000000000000000000000000000081526001600160a01b03861660048201526024810185905260448101849052606401610bb6565b505083547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03939093169290921783556001830155600290910155565b612180828261284e565b61218a8282612858565b6121948282612895565b61219e8282612989565b6121a88282612bdc565b6121b28282612c26565b6106c28282612d13565b600354156106c257600180546003546040517feb056bbb00000000000000000000000000000000000000000000000000000000815260048101919091526001600160a01b03858116602483015260448201859052606482019390935291169063eb056bbb906084015b600060405180830381600087803b15801561223f57600080fd5b505af1158015612253573d6000803e3d6000fd5b505050505050565b6122658282612e29565b61226f8282612ecb565b6122798282612eed565b6106c28282613137565b60006001600160a01b03841615801561229a575082155b80156122a4575081155b905060006001600160a01b038516158015906122c05750600084115b80156122cc5750600083115b9050811580156122da575080155b1561232a576040517ff5deb5dc0000000000000000000000000000000000000000000000000000000081526001600160a01b03861660048201526024810185905260448101849052606401610bb6565b600386018390556001860184905581156123515760006002870181905560048701556123bd565b8560040154600003612378576000600287015561236e8342615067565b60048701556123bd565b85546001600160a01b038681169116146123bd5785546000906123a4906001600160a01b031687613164565b60028801549091506123b69082613170565b6002880155505b505083547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0393909316929092179092555050565b808214801561240857508115155b15612442576040517f0fb49edb00000000000000000000000000000000000000000000000000000000815260048101839052602401610bb6565b60028290556003819055604051819083907ff950a929751d87db181a0a517df21bb3ecd433abba584594402db4b58a55483590600090a35050565b600054610100900460ff166124e85760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b80516124f3906131e6565b6124fb6132c8565b612508816020015161333d565b61251581604001516133b1565b6125228160600151613425565b61252f8160800151613499565b61253c8160a0015161350d565b61254581613581565b50565b600054610100900460ff166125b35760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b6125bc82611e2d565b61081181610f8d565b60008080836226496581018262023ab1600483020590506004600362023ab18302010590910390600062164b09610fa0600185010205905060046105b58202058303601f019250600061098f846050028161262257612622615024565b0590506000605061098f83020585039050600b82057fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcf94909401606402929092018301996002600c90940290910392909201975095509350505050565b600081600114806126905750816003145b8061269b5750816005145b806126a65750816007145b806126b15750816008145b806126bc575081600a145b806126c7575081600c145b156126d45750601f610db2565b816002146126e45750601e610db2565b6126ed836135ec565b6126f857601c6126fb565b601d5b60ff169392505050565b600081815260018301602052604081205480156127ee57600061272960018361507a565b855490915060009061273d9060019061507a565b90508181146127a257600086600001828154811061275d5761275d614cd7565b906000526020600020015490508087600001848154811061278057612780614cd7565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806127b3576127b361508d565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610db2565b6000915050610db2565b5092915050565b600081815260018301602052604081205461284657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610db2565b506000610db2565b6106c28282613628565b60045460ff16156106c2576040517fc0f2312800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5a6005556040805160808101825260065480825260075460208301526008549282019290925260095460608201529060009015806128d4575081513a11155b9050806129195781516040517fcbb35eb70000000000000000000000000000000000000000000000000000000081523a60048201526024810191909152604401610bb6565b6000612925483a61507a565b90506000836020015160001480612940575083602001518211155b9050806122535760208401516040517f56e5387f000000000000000000000000000000000000000000000000000000008152610bb6918491600401918252602082015260400190565b600a54600b54600c54600e5460ff90931692428211156129de576040517f013ce60b00000000000000000000000000000000000000000000000000000000815242600482015260248101839052604401610bb6565b60008460028111156129f2576129f26147dc565b03612ac45782600003612a0757505050505050565b80600003612a2157612a198342615067565b600d55612253565b6000612a2d834261507a565b90506000612a3b8583615053565b90506000612a498683614f08565b612a53908461507a565b905083811115612a98576040517f013ce60b00000000000000000000000000000000000000000000000000000000815242600482015260248101869052604401610bb6565b85612aa4836001615067565b612aae9190614f08565b612ab89086615067565b600d5550612253915050565b814210158015612add5750612ad98183615067565b4211155b15612aec57612a198284613694565b60006001856002811115612b0257612b026147dc565b14612b1557612b1042612041565b612b1e565b612b1e8361202a565b90506000612b2c848361372c565b905080421015612b71576040517f013ce60b00000000000000000000000000000000000000000000000000000000815242600482015260248101829052604401610bb6565b6000612b7d8483615067565b90504281108015612bc3576040517f013ce60b00000000000000000000000000000000000000000000000000000000815242600482015260248101839052604401610bb6565b612bcd8388613694565b600d5550505050505050505050565b612be582610ef4565b6106c2576040517f7a2410450000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610bb6565b6000612c3183611a4b565b80519091506001600160a01b0316612c4857505050565b6000836001600160a01b031682600001516001600160a01b031614612c8457612c7f612c78858460000151613164565b8490613170565b612c86565b825b9050600082602001518210158015612cae575060408301511580612cae575082604001518211155b905080610710578251602084015160408086015190517f7c63a4b00000000000000000000000000000000000000000000000000000000081526001600160a01b0390931660048401526024830185905260448301919091526064820152608401610bb6565b6000612d1e83611df9565b6040805160a08101825282546001600160a01b031680825260018401546020830152600284015492820192909252600383015460608201526004909201546080830152909150612d6d57505050565b6000836001600160a01b031682600001516001600160a01b031614612da257612d9d612c78858460000151613164565b612da4565b825b9050600082608001514210612dba576000612dc0565b82604001515b612dca9083615067565b9050826020015181111561071057825160208401516040517fb8858d5d0000000000000000000000000000000000000000000000000000000081526001600160a01b039092166004830152602482015260448101829052606401610bb6565b6000612e3483611df9565b80549091506001600160a01b0316612e4b57505050565b80546000906001600160a01b03858116911614612e81578154612e7c90612c789086906001600160a01b0316613164565b612e83565b825b905081600401544210612eac57600060028301556003820154612ea69042615067565b60048301555b80826002016000828254612ec09190615067565b909155505050505050565b600d54600003612ed9575050565b612ee4600d54613754565b50506000600d55565b600554600003612f29576040517f1f5b8fc600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516080810182526006548152600754602082015260085491810191909152600954606082015260005a600554612f62919061507a565b90506000612f703a83614f08565b90506000836040015160001480612f8b575083604001518211155b905080612fd5578184604001516040517faf258ef2000000000000000000000000000000000000000000000000000000008152600401610bb6929190918252602082015260400190565b6000600555606084015115801590612fed5750600085115b156122535760006130c0306001600160a01b0316634fd49efd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613035573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061305991906150bc565b6001600160a01b03166317fcb39b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613096573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130ba91906150bc565b88613164565b905060006130ce8483613789565b905060006130dc8289613832565b9050866060015181111561312c5760608701516040517f0297747f000000000000000000000000000000000000000000000000000000008152610bb6918391600401918252602082015260400190565b505050505050505050565b6040517f68f46c45a243a0e9065a97649faf9a5afe1692f2679e650c2f853b9cd734cc0e90600090a15050565b6000610f2b83836138fb565b6000828202831580159061319357508284828161318f5761318f615024565b0414155b156131d4576040517fe8e4a4fa0000000000000000000000000000000000000000000000000000000081526004810185905260248101849052604401610bb6565b670de0b6b3a764000090049392505050565b600054610100900460ff166132515760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b6132bf81600001516001600160a01b031663d09edf316040518163ffffffff1660e01b8152600401602060405180830381865afa158015613296573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132ba91906150bc565b613b09565b61254581613b7d565b600054610100900460ff166133335760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b61333b613c35565b565b600054610100900460ff166133a85760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b61254581613ca0565b600054610100900460ff1661341c5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b61254581613d27565b600054610100900460ff166134905760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b61254581613dae565b600054610100900460ff166135045760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b61254581613e6e565b600054610100900460ff166135785760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b61254581613f5e565b600054610100900460ff166125455760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b60006135f96004836150d9565b15801561360f575061360c6064836150d9565b15155b80610db25750613621610190836150d9565b1592915050565b600254156106c2576001546002546040517feb056bbb00000000000000000000000000000000000000000000000000000000815260048101919091526001600160a01b03848116602483015260448201849052600060648301529091169063eb056bbb90608401612225565b6000806000806136a38661404e565b9194509250905060006136b68684615067565b905060006136c5600c836150d9565b905060006136d4600c84615053565b6136de9087615067565b905060006002600a5460ff1660028111156136fb576136fb6147dc565b146137065784613710565b613710828461267f565b905061371e8a83858461406d565b9a9950505050505050505050565b600080600061373a4261404e565b509150915061374b8583838761406d565b95945050505050565b600c8190556040518181527ff90744bee56935ec5acc9de37b89c0c545298c667ee417bd9469e9c6836ad06490602001611736565b600082820283158015906137ac5750828482816137a8576137a8615024565b0414155b156137ed576040517fe8e4a4fa0000000000000000000000000000000000000000000000000000000081526004810185905260248101849052604401610bb6565b801561382857670de0b6b3a76400007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820104600101612022565b6000949350505050565b60008160000361386e576040517fb8a2f92100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260000361387e57506000610db2565b670de0b6b3a76400008381029084828161389a5761389a615024565b04146138dc576040517fea7b49e60000000000000000000000000000000000000000000000000000000081526004810185905260248101829052604401610bb6565b8260018203816138ee576138ee615024565b0460010191505092915050565b600080600160009054906101000a90046001600160a01b03166001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613951573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061397591906150bc565b90506001600160a01b0381166139c6576001546040517f38d2baae0000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610bb6565b60006139d0614095565b90508051600014613a6157816001600160a01b031663355efdd96139f387614115565b6139fc87614115565b846040518463ffffffff1660e01b8152600401613a1b939291906150ed565b602060405180830381865afa158015613a38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a5c9190614f90565b61374b565b816001600160a01b031663ac41865a613a7987614115565b613a8287614115565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b03928316600482015291166024820152604401602060405180830381865afa158015613ae5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061374b9190614f90565b600054610100900460ff16613b745760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b61254581614149565b600054610100900460ff16613be85760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b8051600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909216919091179055602081015160408201516125459190611b30565b600054610100900460ff1661333b5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b600054610100900460ff16613d0b5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b6125458160000151826020015183604001518460600151611ecf565b600054610100900460ff16613d925760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b61254581600001518260200151836040015184606001516110da565b600054610100900460ff16613e195760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b8051613e24906116c6565b60005b8160200151518110156106c257613e5c82602001518281518110613e4d57613e4d614cd7565b602002602001015160016114b3565b80613e6681614d35565b915050613e27565b600054610100900460ff16613ed95760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b8051805160208201516040830151613ef2929190611d9d565b60005b82602001515181101561081157600083602001518281518110613f1a57613f1a614cd7565b60200260200101519050600081602001519050613f4982600001518260000151836020015184604001516115c6565b50508080613f5690614d35565b915050613ef5565b600054610100900460ff16613fc95760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b8051805160208201516040830151613fe2929190611c86565b60005b8260200151518110156108115760008360200151828151811061400a5761400a614cd7565b60200260200101519050600081602001519050614039826000015182600001518360200151846040015161198b565b5050808061404690614d35565b915050613fe5565b600080806140606201518085046125c5565b9196909550909350915050565b600061374b84848461407e896141f4565b6140878a614212565b6140908b61422e565b61423b565b606060006140a1614297565b9050368111156140bf57505060408051600081526020810190915290565b8067ffffffffffffffff8111156140d8576140d8614507565b6040519080825280601f01601f191660200182016040528015614102576020820181803683370190505b5091508060208236030360208401375090565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b038316146141415781610db2565b610db26142b2565b600054610100900460ff166141b45760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b600080546001600160a01b0390921662010000027fffffffffffffffffffff0000000000000000000000000000000000000000ffff909216919091179055565b60008061420462015180846150d9565b9050610f2b610e1082615053565b600080614221610e10846150d9565b9050610f2b603c82615053565b6000610db2603c836150d9565b600081614249603c85614f08565b614255610e1087614f08565b620151806142648b8b8b61433e565b61426e9190614f08565b6142789190615067565b6142829190615067565b61428c9190615067565b979650505050505050565b600060243610156142a85750600090565b50601f1936013590565b600154604080517f17fcb39b00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b0316916317fcb39b9160048083019260209291908290030181865afa158015614315573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061433991906150bc565b905090565b60006107b284101561434f57600080fd5b838383600062253d8c60046064600c614369600e88615119565b6143739190615139565b61437f886113246151a1565b61438991906151a1565b6143939190615139565b61439e9060036151c9565b6143a89190615139565b600c806143b6600e88615119565b6143c09190615139565b6143cb90600c6151c9565b6143d6600288615119565b6143e09190615119565b6143ec9061016f6151c9565b6143f69190615139565b6004600c614405600e89615119565b61440f9190615139565b61441b896112c06151a1565b61442591906151a1565b614431906105b56151c9565b61443b9190615139565b614447617d4b87615119565b61445191906151a1565b61445b91906151a1565b6144659190615119565b61446f9190615119565b98975050505050505050565b6001600160a01b038116811461254557600080fd5b803561449b8161447b565b919050565b6000602082840312156144b257600080fd5b8135610f2b8161447b565b803560ff8116811461449b57600080fd5b600080600080608085870312156144e457600080fd5b6144ed856144bd565b966020860135965060408601359560600135945092505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516080810167ffffffffffffffff8111828210171561455957614559614507565b60405290565b6040805190810167ffffffffffffffff8111828210171561455957614559614507565b60405160c0810167ffffffffffffffff8111828210171561455957614559614507565b604051601f8201601f1916810167ffffffffffffffff811182821017156145ce576145ce614507565b604052919050565b600067ffffffffffffffff8211156145f0576145f0614507565b5060051b60200190565b600082601f83011261460b57600080fd5b8135602061462061461b836145d6565b6145a5565b82815260059290921b8401810191818101908684111561463f57600080fd5b8286015b848110156146635780356146568161447b565b8352918301918301614643565b509695505050505050565b801515811461254557600080fd5b6000806040838503121561468f57600080fd5b823567ffffffffffffffff808211156146a757600080fd5b6146b3868387016145fa565b93506020915081850135818111156146ca57600080fd5b85019050601f810186136146dd57600080fd5b80356146eb61461b826145d6565b81815260059190911b8201830190838101908883111561470a57600080fd5b928401925b828410156147315783356147228161466e565b8252928401929084019061470f565b80955050505050509250929050565b6000806000806080858703121561475657600080fd5b84356147618161447b565b935060208501356147718161447b565b93969395505050506040820135916060013590565b80356002811061449b57600080fd5b6000602082840312156147a757600080fd5b610f2b82614786565b600080604083850312156147c357600080fd5b82356147ce8161447b565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160028310614846577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b6000806040838503121561485f57600080fd5b50508035926020909101359150565b60006060828403121561488057600080fd5b6040516060810181811067ffffffffffffffff821117156148a3576148a3614507565b60405290508082356148b48161447b565b8082525060208301356020820152604083013560408201525092915050565b6000608082840312156148e557600080fd5b6148ed614536565b90508135815260208201356020820152604082013560408201526060820135606082015292915050565b60006080828403121561492957600080fd5b614931614536565b905061493c826144bd565b815260208201356020820152604082013560408201526060820135606082015292915050565b60006040828403121561497457600080fd5b61497c61455f565b905061498782614786565b8152602082013567ffffffffffffffff8111156149a357600080fd5b6149af848285016145fa565b60208301525092915050565b6000608082840312156149cd57600080fd5b6149d561455f565b905081356149e28161447b565b81526149f1836020840161486e565b602082015292915050565b60006080808385031215614a0f57600080fd5b614a1761455f565b9150614a23848461486e565b8252606083013567ffffffffffffffff811115614a3f57600080fd5b8301601f81018513614a5057600080fd5b80356020614a6061461b836145d6565b82815260079290921b83018101918181019088841115614a7f57600080fd5b938201935b83851015614aa557614a9689866149bb565b82529385019390820190614a84565b808388015250505050505092915050565b60006080808385031215614ac957600080fd5b614ad161455f565b9150614add848461486e565b8252606083013567ffffffffffffffff811115614af957600080fd5b8301601f81018513614b0a57600080fd5b80356020614b1a61461b836145d6565b82815260079290921b83018101918181019088841115614b3957600080fd5b938201935b83851015614aa557614b5089866149bb565b82529385019390820190614b3e565b600080600060608486031215614b7457600080fd5b833567ffffffffffffffff80821115614b8c57600080fd5b908501906101c08288031215614ba157600080fd5b614ba9614582565b614bb3888461486e565b8152614bc288606085016148d3565b6020820152614bd48860e08501614917565b604082015261016083013582811115614bec57600080fd5b614bf889828601614962565b60608301525061018083013582811115614c1157600080fd5b614c1d898286016149fc565b6080830152506101a083013582811115614c3657600080fd5b614c4289828601614ab6565b60a0830152509450614c5991505060208501614490565b9150614c6760408501614490565b90509250925092565b600080600060608486031215614c8557600080fd5b8335614c908161447b565b95602085013595506040909401359392505050565b60008060008060808587031215614cbb57600080fd5b5050823594602084013594506040840135936060013592509050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614d6657614d66614d06565b5060010190565b60005b83811015614d88578181015183820152602001614d70565b50506000910152565b60008151808452614da9816020860160208601614d6d565b601f01601f19169290920160200192915050565b6001600160a01b0384168152606060208201526000614ddf6060830185614d91565b9050826040830152949350505050565b600060208284031215614e0157600080fd5b815167ffffffffffffffff80821115614e1957600080fd5b818401915084601f830112614e2d57600080fd5b815181811115614e3f57614e3f614507565b614e526020601f19601f840116016145a5565b9150808252856020828501011115614e6957600080fd5b614e7a816020840160208601614d6d565b50949350505050565b600081518084526020808501945080840160005b83811015614eb357815187529582019590820190600101614e97565b509495945050505050565b6001600160a01b03841681527fffffffff000000000000000000000000000000000000000000000000000000008316602082015260606040820152600061374b6060830184614e83565b8082028115828204841417610db257610db2614d06565b606080825284519082018190526000906020906080840190828801845b82811015614f615781516001600160a01b031684529284019290840190600101614f3c565b50505083810382850152614f758187614e83565b925050506001600160a01b0383166040830152949350505050565b600060208284031215614fa257600080fd5b5051919050565b60006001600160a01b0380871683528086166020840152507fffffffff000000000000000000000000000000000000000000000000000000008416604083015260806060830152614ffd6080830184614e83565b9695505050505050565b60006020828403121561501957600080fd5b8151610f2b8161466e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261506257615062615024565b500490565b80820180821115610db257610db2614d06565b81810381811115610db257610db2614d06565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000602082840312156150ce57600080fd5b8151610f2b8161447b565b6000826150e8576150e8615024565b500690565b60006001600160a01b0380861683528085166020840152506060604083015261374b6060830184614d91565b81810360008312801583831316838312821617156127f8576127f8614d06565b60008261514857615148615024565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f80000000000000000000000000000000000000000000000000000000000000008314161561519c5761519c614d06565b500590565b80820182811260008312801582168215821617156151c1576151c1614d06565b505092915050565b808202600082127f80000000000000000000000000000000000000000000000000000000000000008414161561520157615201614d06565b8181058314821517610db257610db2614d0656fea2646970667358221220b70390f69b4e407ce3160110958c9fbec684ea781f058372c1093be17fc2994364736f6c63430008110033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102265760003560e01c80636b1239191161012a578063b187bd26116100bd578063d45a76cf1161008c578063e6b5be9811610071578063e6b5be9814610648578063e97b80711461065b578063f9eaee0d1461066e57600080fd5b8063d45a76cf14610622578063db20de821461063557600080fd5b8063b187bd26146105c8578063c267621e146105e5578063d09edf31146105f6578063d3feb6021461060f57600080fd5b806390333ba8116100f957806390333ba814610515578063a0c3774f14610528578063a33741771461053b578063a5900c4d1461056e57600080fd5b80636b123919146104d45780637125590a146104e75780637cbd3a56146104fa5780638456cb591461050d57600080fd5b80633f4ba83a116101bd5780634fd49efd1161018c5780635670e2ce116101715780635670e2ce146104415780635ea54eee1461045c5780636aacaad81461048857600080fd5b80634fd49efd146103de57806351a424b11461040957600080fd5b80633f4ba83a14610374578063423a4b401461037c57806342d4693e1461038f5780634a45a3a8146103a957600080fd5b8063221a8c68116101f9578063221a8c68146102975780632384c32d1461033b57806330eae5721461034e5780633bd9ef281461036157600080fd5b80630ef917ed1461022b5780630fe105e814610240578063119a5e96146102535780632197238414610284575b600080fd5b61023e6102393660046144a0565b610681565b005b61023e61024e3660046144ce565b6106c6565b61025b610717565b6040805160ff909516855260208501939093529183015260608201526080015b60405180910390f35b61023e61029236600461467c565b61074e565b6103096102a53660046144a0565b6001600160a01b039081166000908152601b6020908152604091829020825160a08101845281549094168085526001820154928501839052600282015493850184905260038201546060860181905260049092015460809095018590529491939091565b604080516001600160a01b0390961686526020860194909452928401919091526060830152608082015260a00161027b565b61023e610349366004614740565b610816565b61023e61035c366004614795565b61085d565b61023e61036f3660046147b0565b6108b2565b61023e61099e565b61023e61038a366004614740565b610a5b565b600f5461039c9060ff1681565b60405161027b919061480b565b6103d07f4f1a5aef466c18f2eefd210f80b744aa3b40590af293e84b695be7d70fd862b381565b60405190815260200161027b565b6001546103f1906001600160a01b031681565b6040516001600160a01b03909116815260200161027b565b61041c6104173660046144a0565b610aa2565b604080516001600160a01b03909416845260208401929092529082015260600161027b565b6002546003546040805192835260208301919091520161027b565b60065460075460085460095460408051948552602085019390935291830152606082015260800161027b565b6103096040805160a0810182526016546001600160a01b03168082526017546020830181905260185493830184905260195460608401819052601a546080909401849052919490939290565b601c546103f1906001600160a01b031681565b61023e6104f536600461484c565b610acb565b61023e610508366004614b5f565b610b0e565b61023e610c92565b61023e610523366004614c70565b610d53565b6103d06105363660046144a0565b610d98565b61041c604080516060810182526012546001600160a01b0316808252601354602083018190526014549290930182905292565b61041c61057c3660046144a0565b6001600160a01b03808216600090815260156020908152604091829020825160608101845281549094168085526001820154928501839052600290910154939092018390529093909250565b6004546105d59060ff1681565b604051901515815260200161027b565b601d546001600160a01b03166103f1565b6000546103f1906201000090046001600160a01b031681565b61023e61061d366004614c70565b610db8565b6103096106303660046144a0565b610dfd565b61023e6106433660046144a0565b610e6c565b61023e610656366004614ca5565b610ead565b601d546103f1906001600160a01b031681565b6105d561067c3660046144a0565b610ef4565b61068a81610f32565b6106b9336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b6106c282610f8d565b5050565b6106d58460ff1684848461102f565b610704336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b610710858585856110da565b5050505050565b600a5460009081908190819060ff166002811115610737576107376147dc565b600b54600c54600e54935093509350935090919293565b61077c336000357fffffffff0000000000000000000000000000000000000000000000000000000016611497565b80518251146107b7576040517f5d32021a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8251811015610811576107ff8382815181106107d8576107d8614cd7565b60200260200101518383815181106107f2576107f2614cd7565b60200260200101516114b3565b8061080981614d35565b9150506107ba565b505050565b6108228484848461155d565b610851336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b610710858585856115c6565b61087a816001811115610872576108726147dc565b60ff1661167f565b6108a9336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b6106c2826116c6565b6108bc8282611741565b6108eb336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b816000036108ff576108fc83610d98565b91505b61090983836117b0565b600154601c546001600160a01b0391821691634ae00041911661092c8686611834565b60006040518463ffffffff1660e01b815260040161094c93929190614dbd565b6000604051808303816000875af115801561096b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109939190810190614def565b506108118383611977565b6109cc336000357fffffffff0000000000000000000000000000000000000000000000000000000016611497565b60045460ff16610a08576040517f9e6558bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690556040517fa45f47fdea8a1efdd9029a5691c7f759c32b7c698632b563573e155625d1693390600090a1565b610a678484848461155d565b610a96336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b6107108585858561198b565b600080600080610ab185611a4b565b805160208201516040909201519097919650945092505050565b610ad58282611ad6565b610b04336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b6108118383611b30565b600054610100900460ff1615808015610b2e5750600054600160ff909116105b80610b485750303b158015610b48575060005460ff166001145b610bbf5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015610c1d57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b610c28848484611b75565b8015610c8c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a15b50505050565b610cc0336000357fffffffff0000000000000000000000000000000000000000000000000000000016611497565b60045460ff1615610cfd576040517fc0f2312800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556040517f9e87fac88ff661f02d44f95383c817fece4bce600a3dab7a54406878b965e75290600090a1565b610d5e838383611bf4565b610d8d336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b610c8c848484611c86565b601d54600090610db29083906001600160a01b0316611cdc565b92915050565b610dc3838383611bf4565b610df2336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b610c8c848484611d9d565b600080600080600080610e0f87611df9565b6040805160a08101825282546001600160a01b031680825260018401546020830181905260028501549383018490526003850154606084018190526004909501546080909301839052909b909a5091985091965090945092505050565b610e7581610f32565b610ea4336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b6106c282611e2d565b610eb98484848461102f565b610ee8336000357fffffffff000000000000000000000000000000000000000000000000000000001683610f46565b61071085858585611ecf565b600080610f02601084611f6a565b90506001600f5460ff166001811115610f1d57610f1d6147dc565b14610f29578015610f2b565b805b9392505050565b6060610db2826001600160a01b031661167f565b610f51838383611f8c565b610811578282826040517f960c80da000000000000000000000000000000000000000000000000000000008152600401610bb693929190614ebe565b6001600160a01b038116610fcd576040517fdb6cf18100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601d80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517f0c7d25a41bb896a3d198b4b4593a58cb7f37d8340b0b58bffa244676e2ef803a90600090a250565b60408051600480825260a0820190925260609160208201608080368337019050509050848160008151811061106657611066614cd7565b602002602001018181525050838160018151811061108657611086614cd7565b60200260200101818152505082816002815181106110a6576110a6614cd7565b60200260200101818152505081816003815181106110c6576110c6614cd7565b602002602001018181525050949350505050565b60ff84166111d65760008111806110f15750600082115b156111d1578260000361113c576040517fbea499cb00000000000000000000000000000000000000000000000000000000815260ff8516600482015260248101849052604401610bb6565b80158061114857508281115b1561118b576040517f9e12fccf00000000000000000000000000000000000000000000000000000000815260ff8516600482015260248101829052604401610bb6565b816000036111d1576040517fad0d7eb200000000000000000000000000000000000000000000000000000000815260ff8516600482015260248101839052604401610bb6565b6113ec565b8260000361121c576040517fbea499cb00000000000000000000000000000000000000000000000000000000815260ff8516600482015260248101849052604401610bb6565b80158061123457506112316224ea0084614f08565b81115b15611277576040517f9e12fccf00000000000000000000000000000000000000000000000000000000815260ff8516600482015260248101829052604401610bb6565b816000036112bd576040517fad0d7eb200000000000000000000000000000000000000000000000000000000815260ff8516600482015260248101839052604401610bb6565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60ff85160161133657601c6112f28361202a565b11156111d1576040517fad0d7eb200000000000000000000000000000000000000000000000000000000815260ff8516600482015260248101839052604401610bb6565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe60ff8516016113b55761136982612041565b6113728361202a565b146111d1576040517fad0d7eb200000000000000000000000000000000000000000000000000000000815260ff8516600482015260248101839052604401610bb6565b6040517f33a738bc00000000000000000000000000000000000000000000000000000000815260ff85166004820152602401610bb6565b8360ff166002811115611401576114016147dc565b600a80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600183600281111561143b5761143b6147dc565b0217905550600b839055600c829055600e8190556040805160ff8616815260208101859052908101839052606081018290527f182fd6fa2a8560221614c1396dd4fcc78d26dfacf821a6afb61d25876057e41290608001610c83565b6040805160008152602081019091526106c29083908390610f46565b6001600160a01b0382166114f3576040517fc41a13ec00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8061150857611503601083612064565b611513565b611513601083612079565b50816001600160a01b03167f6264362e9de26efefda321dfaeb4e4a9090deef40c5435fad8e9e2e306889a1c82604051611551911515815260200190565b60405180910390a25050565b60408051600480825260a0820190925260609160208201608080368337019050509050846001600160a01b03168160008151811061159d5761159d614cd7565b602002602001018181525050836001600160a01b03168160018151811061108657611086614cd7565b6001600160a01b038416611606576040517fe7ba3e4a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038416600090815260156020526040902061162a9084848461208e565b604080516001600160a01b03858116825260208201859052918101839052908516907ff099617c054d3a65e02a9c3b786f23cc03d5982bc7cfae84dff0408049cf17079060600160405180910390a250505050565b6040805160018082528183019092526060916020808301908036833701905050905081816000815181106116b5576116b5614cd7565b602002602001018181525050919050565b600f80548291907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660018381811115611702576117026147dc565b02179055507f216b6a9618d607ba436d0f2e17e9a83e70929adff805ac2385d67401360e551a81604051611736919061480b565b60405180910390a150565b6040805160028082526060808301845292602083019080368337019050509050826001600160a01b03168160008151811061177e5761177e614cd7565b602002602001018181525050818160018151811061179e5761179e614cd7565b60200260200101818152505092915050565b6117ba8282612176565b6001600160a01b0382166117fa576040517fc0e0f12200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806000036106c2576040517f1463acbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160018082528183019092526060916000919060208083019080368337019050509050838160008151811061186e5761186e614cd7565b6001600160a01b03929092166020928302919091019091015260408051600180825281830190925260009181602001602082028036833701905050905083816000815181106118bf576118bf614cd7565b60209081029190910101526001546040517f6daefab6000000000000000000000000000000000000000000000000000000009161190e91859185916001600160a01b0390911690602401614f1f565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091529250505092915050565b61198182826121bc565b6106c2828261225b565b6001600160a01b0384166119cb576040517f1de0c9c700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b0384166000908152601b602052604090206119ef90848484612283565b826001600160a01b0316846001600160a01b03167f1b5c5e27ed5443e409bae85849d41d7bf12d5352e8fddb3728b6408f836e14488484604051611a3d929190918252602082015260400190565b60405180910390a350505050565b611a78604051806060016040528060006001600160a01b0316815260200160008152602001600081525090565b6001600160a01b038083166000908152601560205260409020805490911615611aa15780611aa4565b60125b6040805160608101825282546001600160a01b0316815260018301546020820152600290920154908201529392505050565b60408051600280825260608083018452926020830190803683370190505090508260001c81600081518110611b0d57611b0d614cd7565b6020026020010181815250508160001c8160018151811061179e5761179e614cd7565b8115611b6b576040517fade7e16800000000000000000000000000000000000000000000000000000000815260048101839052602401610bb6565b6106c282826123fa565b600054610100900460ff16611be05760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b611be98361247d565b610811838383612548565b60408051600380825260808201909252606091602082018380368337019050509050836001600160a01b031681600081518110611c3357611c33614cd7565b6020026020010181815250508281600181518110611c5357611c53614cd7565b6020026020010181815250508181600281518110611c7357611c73614cd7565b6020026020010181815250509392505050565b611c936016848484612283565b60408051838152602081018390526001600160a01b038516917f6324b5f18e615697a2b44f16d7a649deb0bbbc7cb09dad4c610306105730e7d9910160405180910390a2505050565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b03841603611d1357506001600160a01b03811631610db2565b6040517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa158015611d72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d969190614f90565b9050610db2565b611daa601284848461208e565b604080516001600160a01b0385168152602081018490529081018290527fa80953bdc344b2ebd0bcdd001a3418a8fd1b858bdecf12a4ba5a9366ad65d3459060600160405180910390a1505050565b6001600160a01b038082166000908152601b602052604081208054919290911615611e245780610f2b565b60169392505050565b6001600160a01b038116611e6d576040517f382928fe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b601c80547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0383169081179091556040517ffdbd8fd3124d4abea1394a5bf9d535d8b716508569491ceae023fc8f0221c73a90600090a250565b670de0b6b3a7640000811115611f11576040517fce57496100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60068490556007839055600882905560098190556040805185815260208101859052908101839052606081018290527f746dc5eb53c5de07c40b06d428506d6982ea10c423ac2875abfc44038927d69190608001610c83565b6001600160a01b03811660009081526001830160205260408120541515610f2b565b600080546040517f28522895000000000000000000000000000000000000000000000000000000008152620100009091046001600160a01b031690632852289590611fe1908790309088908890600401614fa9565b602060405180830381865afa158015611ffe573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120229190615007565b949350505050565b600061202261203c6201518084615053565b6125c5565b6000808061205561203c6201518086615053565b5091509150612022828261267f565b6000610f2b836001600160a01b038416612705565b6000610f2b836001600160a01b0384166127ff565b60006001600160a01b0384161580156120a5575082155b80156120af575081155b905060006001600160a01b038516158015906120d357508215806120d35750838310155b9050811580156120e1575080155b15612131576040517fca1f04830000000000000000000000000000000000000000000000000000000081526001600160a01b03861660048201526024810185905260448101849052606401610bb6565b505083547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03939093169290921783556001830155600290910155565b612180828261284e565b61218a8282612858565b6121948282612895565b61219e8282612989565b6121a88282612bdc565b6121b28282612c26565b6106c28282612d13565b600354156106c257600180546003546040517feb056bbb00000000000000000000000000000000000000000000000000000000815260048101919091526001600160a01b03858116602483015260448201859052606482019390935291169063eb056bbb906084015b600060405180830381600087803b15801561223f57600080fd5b505af1158015612253573d6000803e3d6000fd5b505050505050565b6122658282612e29565b61226f8282612ecb565b6122798282612eed565b6106c28282613137565b60006001600160a01b03841615801561229a575082155b80156122a4575081155b905060006001600160a01b038516158015906122c05750600084115b80156122cc5750600083115b9050811580156122da575080155b1561232a576040517ff5deb5dc0000000000000000000000000000000000000000000000000000000081526001600160a01b03861660048201526024810185905260448101849052606401610bb6565b600386018390556001860184905581156123515760006002870181905560048701556123bd565b8560040154600003612378576000600287015561236e8342615067565b60048701556123bd565b85546001600160a01b038681169116146123bd5785546000906123a4906001600160a01b031687613164565b60028801549091506123b69082613170565b6002880155505b505083547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b0393909316929092179092555050565b808214801561240857508115155b15612442576040517f0fb49edb00000000000000000000000000000000000000000000000000000000815260048101839052602401610bb6565b60028290556003819055604051819083907ff950a929751d87db181a0a517df21bb3ecd433abba584594402db4b58a55483590600090a35050565b600054610100900460ff166124e85760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b80516124f3906131e6565b6124fb6132c8565b612508816020015161333d565b61251581604001516133b1565b6125228160600151613425565b61252f8160800151613499565b61253c8160a0015161350d565b61254581613581565b50565b600054610100900460ff166125b35760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b6125bc82611e2d565b61081181610f8d565b60008080836226496581018262023ab1600483020590506004600362023ab18302010590910390600062164b09610fa0600185010205905060046105b58202058303601f019250600061098f846050028161262257612622615024565b0590506000605061098f83020585039050600b82057fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcf94909401606402929092018301996002600c90940290910392909201975095509350505050565b600081600114806126905750816003145b8061269b5750816005145b806126a65750816007145b806126b15750816008145b806126bc575081600a145b806126c7575081600c145b156126d45750601f610db2565b816002146126e45750601e610db2565b6126ed836135ec565b6126f857601c6126fb565b601d5b60ff169392505050565b600081815260018301602052604081205480156127ee57600061272960018361507a565b855490915060009061273d9060019061507a565b90508181146127a257600086600001828154811061275d5761275d614cd7565b906000526020600020015490508087600001848154811061278057612780614cd7565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806127b3576127b361508d565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610db2565b6000915050610db2565b5092915050565b600081815260018301602052604081205461284657508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610db2565b506000610db2565b6106c28282613628565b60045460ff16156106c2576040517fc0f2312800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5a6005556040805160808101825260065480825260075460208301526008549282019290925260095460608201529060009015806128d4575081513a11155b9050806129195781516040517fcbb35eb70000000000000000000000000000000000000000000000000000000081523a60048201526024810191909152604401610bb6565b6000612925483a61507a565b90506000836020015160001480612940575083602001518211155b9050806122535760208401516040517f56e5387f000000000000000000000000000000000000000000000000000000008152610bb6918491600401918252602082015260400190565b600a54600b54600c54600e5460ff90931692428211156129de576040517f013ce60b00000000000000000000000000000000000000000000000000000000815242600482015260248101839052604401610bb6565b60008460028111156129f2576129f26147dc565b03612ac45782600003612a0757505050505050565b80600003612a2157612a198342615067565b600d55612253565b6000612a2d834261507a565b90506000612a3b8583615053565b90506000612a498683614f08565b612a53908461507a565b905083811115612a98576040517f013ce60b00000000000000000000000000000000000000000000000000000000815242600482015260248101869052604401610bb6565b85612aa4836001615067565b612aae9190614f08565b612ab89086615067565b600d5550612253915050565b814210158015612add5750612ad98183615067565b4211155b15612aec57612a198284613694565b60006001856002811115612b0257612b026147dc565b14612b1557612b1042612041565b612b1e565b612b1e8361202a565b90506000612b2c848361372c565b905080421015612b71576040517f013ce60b00000000000000000000000000000000000000000000000000000000815242600482015260248101829052604401610bb6565b6000612b7d8483615067565b90504281108015612bc3576040517f013ce60b00000000000000000000000000000000000000000000000000000000815242600482015260248101839052604401610bb6565b612bcd8388613694565b600d5550505050505050505050565b612be582610ef4565b6106c2576040517f7a2410450000000000000000000000000000000000000000000000000000000081526001600160a01b0383166004820152602401610bb6565b6000612c3183611a4b565b80519091506001600160a01b0316612c4857505050565b6000836001600160a01b031682600001516001600160a01b031614612c8457612c7f612c78858460000151613164565b8490613170565b612c86565b825b9050600082602001518210158015612cae575060408301511580612cae575082604001518211155b905080610710578251602084015160408086015190517f7c63a4b00000000000000000000000000000000000000000000000000000000081526001600160a01b0390931660048401526024830185905260448301919091526064820152608401610bb6565b6000612d1e83611df9565b6040805160a08101825282546001600160a01b031680825260018401546020830152600284015492820192909252600383015460608201526004909201546080830152909150612d6d57505050565b6000836001600160a01b031682600001516001600160a01b031614612da257612d9d612c78858460000151613164565b612da4565b825b9050600082608001514210612dba576000612dc0565b82604001515b612dca9083615067565b9050826020015181111561071057825160208401516040517fb8858d5d0000000000000000000000000000000000000000000000000000000081526001600160a01b039092166004830152602482015260448101829052606401610bb6565b6000612e3483611df9565b80549091506001600160a01b0316612e4b57505050565b80546000906001600160a01b03858116911614612e81578154612e7c90612c789086906001600160a01b0316613164565b612e83565b825b905081600401544210612eac57600060028301556003820154612ea69042615067565b60048301555b80826002016000828254612ec09190615067565b909155505050505050565b600d54600003612ed9575050565b612ee4600d54613754565b50506000600d55565b600554600003612f29576040517f1f5b8fc600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516080810182526006548152600754602082015260085491810191909152600954606082015260005a600554612f62919061507a565b90506000612f703a83614f08565b90506000836040015160001480612f8b575083604001518211155b905080612fd5578184604001516040517faf258ef2000000000000000000000000000000000000000000000000000000008152600401610bb6929190918252602082015260400190565b6000600555606084015115801590612fed5750600085115b156122535760006130c0306001600160a01b0316634fd49efd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613035573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061305991906150bc565b6001600160a01b03166317fcb39b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613096573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130ba91906150bc565b88613164565b905060006130ce8483613789565b905060006130dc8289613832565b9050866060015181111561312c5760608701516040517f0297747f000000000000000000000000000000000000000000000000000000008152610bb6918391600401918252602082015260400190565b505050505050505050565b6040517f68f46c45a243a0e9065a97649faf9a5afe1692f2679e650c2f853b9cd734cc0e90600090a15050565b6000610f2b83836138fb565b6000828202831580159061319357508284828161318f5761318f615024565b0414155b156131d4576040517fe8e4a4fa0000000000000000000000000000000000000000000000000000000081526004810185905260248101849052604401610bb6565b670de0b6b3a764000090049392505050565b600054610100900460ff166132515760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b6132bf81600001516001600160a01b031663d09edf316040518163ffffffff1660e01b8152600401602060405180830381865afa158015613296573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132ba91906150bc565b613b09565b61254581613b7d565b600054610100900460ff166133335760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b61333b613c35565b565b600054610100900460ff166133a85760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b61254581613ca0565b600054610100900460ff1661341c5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b61254581613d27565b600054610100900460ff166134905760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b61254581613dae565b600054610100900460ff166135045760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b61254581613e6e565b600054610100900460ff166135785760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b61254581613f5e565b600054610100900460ff166125455760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b60006135f96004836150d9565b15801561360f575061360c6064836150d9565b15155b80610db25750613621610190836150d9565b1592915050565b600254156106c2576001546002546040517feb056bbb00000000000000000000000000000000000000000000000000000000815260048101919091526001600160a01b03848116602483015260448201849052600060648301529091169063eb056bbb90608401612225565b6000806000806136a38661404e565b9194509250905060006136b68684615067565b905060006136c5600c836150d9565b905060006136d4600c84615053565b6136de9087615067565b905060006002600a5460ff1660028111156136fb576136fb6147dc565b146137065784613710565b613710828461267f565b905061371e8a83858461406d565b9a9950505050505050505050565b600080600061373a4261404e565b509150915061374b8583838761406d565b95945050505050565b600c8190556040518181527ff90744bee56935ec5acc9de37b89c0c545298c667ee417bd9469e9c6836ad06490602001611736565b600082820283158015906137ac5750828482816137a8576137a8615024565b0414155b156137ed576040517fe8e4a4fa0000000000000000000000000000000000000000000000000000000081526004810185905260248101849052604401610bb6565b801561382857670de0b6b3a76400007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820104600101612022565b6000949350505050565b60008160000361386e576040517fb8a2f92100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260000361387e57506000610db2565b670de0b6b3a76400008381029084828161389a5761389a615024565b04146138dc576040517fea7b49e60000000000000000000000000000000000000000000000000000000081526004810185905260248101829052604401610bb6565b8260018203816138ee576138ee615024565b0460010191505092915050565b600080600160009054906101000a90046001600160a01b03166001600160a01b0316632630c12f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613951573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061397591906150bc565b90506001600160a01b0381166139c6576001546040517f38d2baae0000000000000000000000000000000000000000000000000000000081526001600160a01b039091166004820152602401610bb6565b60006139d0614095565b90508051600014613a6157816001600160a01b031663355efdd96139f387614115565b6139fc87614115565b846040518463ffffffff1660e01b8152600401613a1b939291906150ed565b602060405180830381865afa158015613a38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a5c9190614f90565b61374b565b816001600160a01b031663ac41865a613a7987614115565b613a8287614115565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b1681526001600160a01b03928316600482015291166024820152604401602060405180830381865afa158015613ae5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061374b9190614f90565b600054610100900460ff16613b745760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b61254581614149565b600054610100900460ff16613be85760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b8051600180547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b03909216919091179055602081015160408201516125459190611b30565b600054610100900460ff1661333b5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b600054610100900460ff16613d0b5760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b6125458160000151826020015183604001518460600151611ecf565b600054610100900460ff16613d925760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b61254581600001518260200151836040015184606001516110da565b600054610100900460ff16613e195760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b8051613e24906116c6565b60005b8160200151518110156106c257613e5c82602001518281518110613e4d57613e4d614cd7565b602002602001015160016114b3565b80613e6681614d35565b915050613e27565b600054610100900460ff16613ed95760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b8051805160208201516040830151613ef2929190611d9d565b60005b82602001515181101561081157600083602001518281518110613f1a57613f1a614cd7565b60200260200101519050600081602001519050613f4982600001518260000151836020015184604001516115c6565b50508080613f5690614d35565b915050613ef5565b600054610100900460ff16613fc95760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b8051805160208201516040830151613fe2929190611c86565b60005b8260200151518110156108115760008360200151828151811061400a5761400a614cd7565b60200260200101519050600081602001519050614039826000015182600001518360200151846040015161198b565b5050808061404690614d35565b915050613fe5565b600080806140606201518085046125c5565b9196909550909350915050565b600061374b84848461407e896141f4565b6140878a614212565b6140908b61422e565b61423b565b606060006140a1614297565b9050368111156140bf57505060408051600081526020810190915290565b8067ffffffffffffffff8111156140d8576140d8614507565b6040519080825280601f01601f191660200182016040528015614102576020820181803683370190505b5091508060208236030360208401375090565b600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001600160a01b038316146141415781610db2565b610db26142b2565b600054610100900460ff166141b45760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608401610bb6565b600080546001600160a01b0390921662010000027fffffffffffffffffffff0000000000000000000000000000000000000000ffff909216919091179055565b60008061420462015180846150d9565b9050610f2b610e1082615053565b600080614221610e10846150d9565b9050610f2b603c82615053565b6000610db2603c836150d9565b600081614249603c85614f08565b614255610e1087614f08565b620151806142648b8b8b61433e565b61426e9190614f08565b6142789190615067565b6142829190615067565b61428c9190615067565b979650505050505050565b600060243610156142a85750600090565b50601f1936013590565b600154604080517f17fcb39b00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b0316916317fcb39b9160048083019260209291908290030181865afa158015614315573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061433991906150bc565b905090565b60006107b284101561434f57600080fd5b838383600062253d8c60046064600c614369600e88615119565b6143739190615139565b61437f886113246151a1565b61438991906151a1565b6143939190615139565b61439e9060036151c9565b6143a89190615139565b600c806143b6600e88615119565b6143c09190615139565b6143cb90600c6151c9565b6143d6600288615119565b6143e09190615119565b6143ec9061016f6151c9565b6143f69190615139565b6004600c614405600e89615119565b61440f9190615139565b61441b896112c06151a1565b61442591906151a1565b614431906105b56151c9565b61443b9190615139565b614447617d4b87615119565b61445191906151a1565b61445b91906151a1565b6144659190615119565b61446f9190615119565b98975050505050505050565b6001600160a01b038116811461254557600080fd5b803561449b8161447b565b919050565b6000602082840312156144b257600080fd5b8135610f2b8161447b565b803560ff8116811461449b57600080fd5b600080600080608085870312156144e457600080fd5b6144ed856144bd565b966020860135965060408601359560600135945092505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516080810167ffffffffffffffff8111828210171561455957614559614507565b60405290565b6040805190810167ffffffffffffffff8111828210171561455957614559614507565b60405160c0810167ffffffffffffffff8111828210171561455957614559614507565b604051601f8201601f1916810167ffffffffffffffff811182821017156145ce576145ce614507565b604052919050565b600067ffffffffffffffff8211156145f0576145f0614507565b5060051b60200190565b600082601f83011261460b57600080fd5b8135602061462061461b836145d6565b6145a5565b82815260059290921b8401810191818101908684111561463f57600080fd5b8286015b848110156146635780356146568161447b565b8352918301918301614643565b509695505050505050565b801515811461254557600080fd5b6000806040838503121561468f57600080fd5b823567ffffffffffffffff808211156146a757600080fd5b6146b3868387016145fa565b93506020915081850135818111156146ca57600080fd5b85019050601f810186136146dd57600080fd5b80356146eb61461b826145d6565b81815260059190911b8201830190838101908883111561470a57600080fd5b928401925b828410156147315783356147228161466e565b8252928401929084019061470f565b80955050505050509250929050565b6000806000806080858703121561475657600080fd5b84356147618161447b565b935060208501356147718161447b565b93969395505050506040820135916060013590565b80356002811061449b57600080fd5b6000602082840312156147a757600080fd5b610f2b82614786565b600080604083850312156147c357600080fd5b82356147ce8161447b565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160028310614846577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b6000806040838503121561485f57600080fd5b50508035926020909101359150565b60006060828403121561488057600080fd5b6040516060810181811067ffffffffffffffff821117156148a3576148a3614507565b60405290508082356148b48161447b565b8082525060208301356020820152604083013560408201525092915050565b6000608082840312156148e557600080fd5b6148ed614536565b90508135815260208201356020820152604082013560408201526060820135606082015292915050565b60006080828403121561492957600080fd5b614931614536565b905061493c826144bd565b815260208201356020820152604082013560408201526060820135606082015292915050565b60006040828403121561497457600080fd5b61497c61455f565b905061498782614786565b8152602082013567ffffffffffffffff8111156149a357600080fd5b6149af848285016145fa565b60208301525092915050565b6000608082840312156149cd57600080fd5b6149d561455f565b905081356149e28161447b565b81526149f1836020840161486e565b602082015292915050565b60006080808385031215614a0f57600080fd5b614a1761455f565b9150614a23848461486e565b8252606083013567ffffffffffffffff811115614a3f57600080fd5b8301601f81018513614a5057600080fd5b80356020614a6061461b836145d6565b82815260079290921b83018101918181019088841115614a7f57600080fd5b938201935b83851015614aa557614a9689866149bb565b82529385019390820190614a84565b808388015250505050505092915050565b60006080808385031215614ac957600080fd5b614ad161455f565b9150614add848461486e565b8252606083013567ffffffffffffffff811115614af957600080fd5b8301601f81018513614b0a57600080fd5b80356020614b1a61461b836145d6565b82815260079290921b83018101918181019088841115614b3957600080fd5b938201935b83851015614aa557614b5089866149bb565b82529385019390820190614b3e565b600080600060608486031215614b7457600080fd5b833567ffffffffffffffff80821115614b8c57600080fd5b908501906101c08288031215614ba157600080fd5b614ba9614582565b614bb3888461486e565b8152614bc288606085016148d3565b6020820152614bd48860e08501614917565b604082015261016083013582811115614bec57600080fd5b614bf889828601614962565b60608301525061018083013582811115614c1157600080fd5b614c1d898286016149fc565b6080830152506101a083013582811115614c3657600080fd5b614c4289828601614ab6565b60a0830152509450614c5991505060208501614490565b9150614c6760408501614490565b90509250925092565b600080600060608486031215614c8557600080fd5b8335614c908161447b565b95602085013595506040909401359392505050565b60008060008060808587031215614cbb57600080fd5b5050823594602084013594506040840135936060013592509050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614d6657614d66614d06565b5060010190565b60005b83811015614d88578181015183820152602001614d70565b50506000910152565b60008151808452614da9816020860160208601614d6d565b601f01601f19169290920160200192915050565b6001600160a01b0384168152606060208201526000614ddf6060830185614d91565b9050826040830152949350505050565b600060208284031215614e0157600080fd5b815167ffffffffffffffff80821115614e1957600080fd5b818401915084601f830112614e2d57600080fd5b815181811115614e3f57614e3f614507565b614e526020601f19601f840116016145a5565b9150808252856020828501011115614e6957600080fd5b614e7a816020840160208601614d6d565b50949350505050565b600081518084526020808501945080840160005b83811015614eb357815187529582019590820190600101614e97565b509495945050505050565b6001600160a01b03841681527fffffffff000000000000000000000000000000000000000000000000000000008316602082015260606040820152600061374b6060830184614e83565b8082028115828204841417610db257610db2614d06565b606080825284519082018190526000906020906080840190828801845b82811015614f615781516001600160a01b031684529284019290840190600101614f3c565b50505083810382850152614f758187614e83565b925050506001600160a01b0383166040830152949350505050565b600060208284031215614fa257600080fd5b5051919050565b60006001600160a01b0380871683528086166020840152507fffffffff000000000000000000000000000000000000000000000000000000008416604083015260806060830152614ffd6080830184614e83565b9695505050505050565b60006020828403121561501957600080fd5b8151610f2b8161466e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261506257615062615024565b500490565b80820180821115610db257610db2614d06565b81810381811115610db257610db2614d06565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b6000602082840312156150ce57600080fd5b8151610f2b8161447b565b6000826150e8576150e8615024565b500690565b60006001600160a01b0380861683528085166020840152506060604083015261374b6060830184614d91565b81810360008312801583831316838312821617156127f8576127f8614d06565b60008261514857615148615024565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83147f80000000000000000000000000000000000000000000000000000000000000008314161561519c5761519c614d06565b500590565b80820182811260008312801582168215821617156151c1576151c1614d06565b505092915050565b808202600082127f80000000000000000000000000000000000000000000000000000000000000008414161561520157615201614d06565b8181058314821517610db257610db2614d0656fea2646970667358221220b70390f69b4e407ce3160110958c9fbec684ea781f058372c1093be17fc2994364736f6c63430008110033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 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.