Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
FxUSDShareableRebalancePool
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity =0.8.20; import { IFxBoostableRebalancePool } from "../../interfaces/f(x)/IFxBoostableRebalancePool.sol"; import { ShareableRebalancePoolV2 } from "./ShareableRebalancePoolV2.sol"; contract FxUSDShareableRebalancePool is ShareableRebalancePoolV2 { /*************** * Constructor * ***************/ constructor( address _fxn, address _ve, address _veHelper, address _minter ) ShareableRebalancePoolV2(_fxn, _ve, _veHelper, _minter) {} /**************************** * Public Mutated Functions * ****************************/ /// @inheritdoc IFxBoostableRebalancePool function withdraw(uint256 _amount, address _receiver) external override { // not allowed to withdraw as fToken in fxUSD. // _withdraw(_msgSender(), _amount, _receiver); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControlUpgradeable.sol"; import "../utils/ContextUpgradeable.sol"; import "../utils/StringsUpgradeable.sol"; import "../utils/introspection/ERC165Upgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable { function __AccessControl_init() internal onlyInitializing { } function __AccessControl_init_unchained() internal onlyInitializing { } struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", StringsUpgradeable.toHexString(account), " is missing role ", StringsUpgradeable.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControlUpgradeable { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.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] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuardUpgradeable is Initializable { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.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 IERC20PermitUpgradeable { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; import "../extensions/IERC20PermitUpgradeable.sol"; import "../../../utils/AddressUpgradeable.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20Upgradeable { using AddressUpgradeable for address; /** * @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(IERC20Upgradeable 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(IERC20Upgradeable token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove(IERC20Upgradeable token, address spender, uint256 value) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } /** * @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(IERC20Upgradeable 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(IERC20Upgradeable 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(IERC20Upgradeable 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( IERC20PermitUpgradeable token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); 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(IERC20Upgradeable 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))) && AddressUpgradeable.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 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 * * 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 v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165Upgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable { function __ERC165_init() internal onlyInitializing { } function __ERC165_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165Upgradeable).interfaceId; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165Upgradeable { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library MathUpgradeable { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.0; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafeCastUpgradeable { /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toUint248(uint256 value) internal pure returns (uint248) { require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits"); return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toUint240(uint256 value) internal pure returns (uint240) { require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits"); return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toUint232(uint256 value) internal pure returns (uint232) { require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits"); return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.2._ */ function toUint224(uint256 value) internal pure returns (uint224) { require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits"); return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toUint216(uint256 value) internal pure returns (uint216) { require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits"); return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toUint208(uint256 value) internal pure returns (uint208) { require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits"); return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toUint200(uint256 value) internal pure returns (uint200) { require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits"); return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toUint192(uint256 value) internal pure returns (uint192) { require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits"); return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toUint184(uint256 value) internal pure returns (uint184) { require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits"); return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toUint176(uint256 value) internal pure returns (uint176) { require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits"); return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toUint168(uint256 value) internal pure returns (uint168) { require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits"); return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toUint160(uint256 value) internal pure returns (uint160) { require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits"); return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toUint152(uint256 value) internal pure returns (uint152) { require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits"); return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toUint144(uint256 value) internal pure returns (uint144) { require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits"); return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toUint136(uint256 value) internal pure returns (uint136) { require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits"); return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v2.5._ */ function toUint128(uint256 value) internal pure returns (uint128) { require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits"); return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toUint120(uint256 value) internal pure returns (uint120) { require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits"); return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toUint112(uint256 value) internal pure returns (uint112) { require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits"); return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toUint104(uint256 value) internal pure returns (uint104) { require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits"); return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.2._ */ function toUint96(uint256 value) internal pure returns (uint96) { require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits"); return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toUint88(uint256 value) internal pure returns (uint88) { require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits"); return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toUint80(uint256 value) internal pure returns (uint80) { require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits"); return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toUint72(uint256 value) internal pure returns (uint72) { require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits"); return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v2.5._ */ function toUint64(uint256 value) internal pure returns (uint64) { require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits"); return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toUint56(uint256 value) internal pure returns (uint56) { require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits"); return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toUint48(uint256 value) internal pure returns (uint48) { require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits"); return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toUint40(uint256 value) internal pure returns (uint40) { require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits"); return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v2.5._ */ function toUint32(uint256 value) internal pure returns (uint32) { require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits"); return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toUint24(uint256 value) internal pure returns (uint24) { require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits"); return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v2.5._ */ function toUint16(uint256 value) internal pure returns (uint16) { require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits"); return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v2.5._ */ function toUint8(uint256 value) internal pure returns (uint8) { require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits"); return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. * * _Available since v3.0._ */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: value must be positive"); return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits * * _Available since v4.7._ */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); require(downcasted == value, "SafeCast: value doesn't fit in 248 bits"); } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits * * _Available since v4.7._ */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); require(downcasted == value, "SafeCast: value doesn't fit in 240 bits"); } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits * * _Available since v4.7._ */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); require(downcasted == value, "SafeCast: value doesn't fit in 232 bits"); } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits * * _Available since v4.7._ */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); require(downcasted == value, "SafeCast: value doesn't fit in 224 bits"); } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits * * _Available since v4.7._ */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); require(downcasted == value, "SafeCast: value doesn't fit in 216 bits"); } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits * * _Available since v4.7._ */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); require(downcasted == value, "SafeCast: value doesn't fit in 208 bits"); } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits * * _Available since v4.7._ */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); require(downcasted == value, "SafeCast: value doesn't fit in 200 bits"); } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits * * _Available since v4.7._ */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); require(downcasted == value, "SafeCast: value doesn't fit in 192 bits"); } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits * * _Available since v4.7._ */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); require(downcasted == value, "SafeCast: value doesn't fit in 184 bits"); } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits * * _Available since v4.7._ */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); require(downcasted == value, "SafeCast: value doesn't fit in 176 bits"); } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits * * _Available since v4.7._ */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); require(downcasted == value, "SafeCast: value doesn't fit in 168 bits"); } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits * * _Available since v4.7._ */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); require(downcasted == value, "SafeCast: value doesn't fit in 160 bits"); } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits * * _Available since v4.7._ */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); require(downcasted == value, "SafeCast: value doesn't fit in 152 bits"); } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits * * _Available since v4.7._ */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); require(downcasted == value, "SafeCast: value doesn't fit in 144 bits"); } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits * * _Available since v4.7._ */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); require(downcasted == value, "SafeCast: value doesn't fit in 136 bits"); } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits * * _Available since v3.1._ */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); require(downcasted == value, "SafeCast: value doesn't fit in 128 bits"); } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits * * _Available since v4.7._ */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); require(downcasted == value, "SafeCast: value doesn't fit in 120 bits"); } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits * * _Available since v4.7._ */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); require(downcasted == value, "SafeCast: value doesn't fit in 112 bits"); } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits * * _Available since v4.7._ */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); require(downcasted == value, "SafeCast: value doesn't fit in 104 bits"); } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits * * _Available since v4.7._ */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); require(downcasted == value, "SafeCast: value doesn't fit in 96 bits"); } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits * * _Available since v4.7._ */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); require(downcasted == value, "SafeCast: value doesn't fit in 88 bits"); } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits * * _Available since v4.7._ */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); require(downcasted == value, "SafeCast: value doesn't fit in 80 bits"); } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits * * _Available since v4.7._ */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); require(downcasted == value, "SafeCast: value doesn't fit in 72 bits"); } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits * * _Available since v3.1._ */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); require(downcasted == value, "SafeCast: value doesn't fit in 64 bits"); } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits * * _Available since v4.7._ */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); require(downcasted == value, "SafeCast: value doesn't fit in 56 bits"); } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits * * _Available since v4.7._ */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); require(downcasted == value, "SafeCast: value doesn't fit in 48 bits"); } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits * * _Available since v4.7._ */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); require(downcasted == value, "SafeCast: value doesn't fit in 40 bits"); } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits * * _Available since v3.1._ */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); require(downcasted == value, "SafeCast: value doesn't fit in 32 bits"); } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits * * _Available since v4.7._ */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); require(downcasted == value, "SafeCast: value doesn't fit in 24 bits"); } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits * * _Available since v3.1._ */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); require(downcasted == value, "SafeCast: value doesn't fit in 16 bits"); } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits * * _Available since v3.1._ */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); require(downcasted == value, "SafeCast: value doesn't fit in 8 bits"); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. * * _Available since v3.0._ */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256"); return int256(value); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMathUpgradeable { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/MathUpgradeable.sol"; import "./math/SignedMathUpgradeable.sol"; /** * @dev String operations. */ library StringsUpgradeable { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = MathUpgradeable.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMathUpgradeable.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, MathUpgradeable.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// 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 EnumerableSetUpgradeable { // 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; // solhint-disable no-inline-assembly /// @title DecrementalFloatingPoint /// /// @dev The real number is `magnitude * 10^{-18 - 9 * exponent}`, where `magnitude` is in range `(0, 10^18]`. /// And the floating point is encoded as: /// /// [ epoch | exponent | magnitude ] /// [ 24 bits | 24 bits | 64 bits ] /// [ MSB LSB ] /// /// Hopefully, the `epoch` and `exponent` won't exceed `type(uint24).max`. library DecrementalFloatingPoint { /// @dev The precision of the `magnitude` in the floating point. uint64 internal constant PRECISION = 1e18; /// @dev The half precision of the `magnitude` in the floating point. uint64 internal constant HALF_PRECISION = 1e9; /// @dev Encode `_epoch`, `_exponent` and `_magnitude` to the floating point. function encode( uint24 _epoch, uint24 _exponent, uint64 _magnitude ) internal pure returns (uint112 prod) { assembly { prod := add(_magnitude, add(shl(64, _exponent), shl(88, _epoch))) } } /// @dev Return the epoch of the floating point. /// @param prod The current encoded floating point. function epoch(uint112 prod) internal pure returns (uint24 _epoch) { assembly { _epoch := shr(88, prod) } } /// @dev Return the exponent of the floating point. /// @param prod The current encoded floating point. function exponent(uint112 prod) internal pure returns (uint24 _exponent) { assembly { _exponent := and(shr(64, prod), 0xffffff) } } /// @dev Return the epoch and exponent of the floating point. /// @param prod The current encoded floating point. function epochAndExponent(uint112 prod) internal pure returns (uint48 _epochExponent) { assembly { _epochExponent := shr(64, prod) } } /// @dev Return the magnitude of the floating point. /// @param prod The current encoded floating point. function magnitude(uint112 prod) internal pure returns (uint64 _magnitude) { assembly { _magnitude := and(prod, 0xffffffffffffffff) } } /// @dev Multiply the floating point by a scalar no more than 1.0. /// /// Caller should make sure `scale` is always smaller than or equals to 1.0 /// /// @param prod The current encoded floating point. /// @param scale The multiplier applied to the product, multiplied by 1e18. function mul(uint112 prod, uint64 scale) internal pure returns (uint112) { uint24 _epoch = epoch(prod); uint24 _exponent = exponent(prod); uint256 _magnitude = magnitude(prod); unchecked { if (scale == 0) { _epoch += 1; _exponent = 0; _magnitude = PRECISION; } else if ((uint256(scale) * _magnitude) / PRECISION < HALF_PRECISION) { _exponent += 1; _magnitude = (_magnitude * uint256(scale)) / HALF_PRECISION; } else { _magnitude = (_magnitude * uint256(scale)) / PRECISION; } } // it is safe to direct convert `_magnitude` to uint64. return encode(_epoch, _exponent, uint64(_magnitude)); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IMultipleRewardAccumulator { /********** * Events * **********/ /// @notice Emitted when user claim pending rewards. /// @param account The address of user. /// @param token The address of token claimed. /// @param receiver The address of token receiver. /// @param amount The amount of token claimed. event Claim(address indexed account, address indexed token, address indexed receiver, uint256 amount); /// @notice Emitted when the reward receiver is updated. /// @param account The address of the account. /// @param oldReceiver The address of the previous reward receiver. /// @param newReceiver The address of the current reward receiver. event UpdateRewardReceiver(address indexed account, address indexed oldReceiver, address indexed newReceiver); /********** * Errors * **********/ /// @dev Thrown when caller claim others reward to another user. error ClaimOthersRewardToAnother(); /************************* * Public View Functions * *************************/ /// @notice The address of default reward receiver for given user. /// @param account The address of user to query. function rewardReceiver(address account) external view returns (address); /// @notice Get the amount of pending rewards. /// @param account The address of user to query. /// @param token The address of reward token to query. /// @return amount The amount of pending rewards. function claimable(address account, address token) external view returns (uint256 amount); /// @notice Get the total amount of rewards claimed from this contract. /// @param account The address of user to query. /// @param token The address of reward token to query. /// @return amount The amount of claimed rewards. function claimed(address account, address token) external view returns (uint256 amount); /**************************** * Public Mutated Functions * ****************************/ /// @notice Set the default reward receiver for the caller. /// @dev When set to address(0), rewards are sent to the caller. /// @param _newReceiver The new receiver address for any rewards claimed via `claim`. function setRewardReceiver(address _newReceiver) external; /// @notice Update the global and user snapshot. /// @param account The address of user to update. function checkpoint(address account) external; /// @notice Claim pending rewards of all active tokens for the caller. function claim() external; /// @notice Claim pending rewards of all active tokens for some user. /// @param account The address of the user. function claim(address account) external; /// @notice Claim pending rewards of all active tokens for the user and transfer to others. /// @param account The address of the user. /// @param receiver The address of the recipient. function claim(address account, address receiver) external; /// @notice Claim pending rewards of historical reward tokens for the caller. /// @param tokens The address list of historical reward tokens to claim. function claimHistorical(address[] memory tokens) external; /// @notice Claim pending rewards of historical reward tokens for some user. /// @param account The address of the user. /// @param tokens The address list of historical reward tokens to claim. function claimHistorical(address account, address[] memory tokens) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable-v4/token/ERC20/IERC20Upgradeable.sol"; import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable-v4/token/ERC20/utils/SafeERC20Upgradeable.sol"; import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable-v4/security/ReentrancyGuardUpgradeable.sol"; import { IMultipleRewardAccumulator } from "./IMultipleRewardAccumulator.sol"; import { DecrementalFloatingPoint } from "../../math/DecrementalFloatingPoint.sol"; import { LinearMultipleRewardDistributor } from "../distributor/LinearMultipleRewardDistributor.sol"; // solhint-disable not-rely-on-time /// @title MultipleRewardCompoundingAccumulator /// @notice `MultipleRewardCompoundingAccumulator` is a reward accumulator for reward distribution in a staking pool. /// In the staking pool, the total stakes will decrease unexpectedly and the user stakes will also decrease proportionally. /// The contract will distribute rewards in proportion to a staker’s share of total stakes with only O(1) complexity. /// /// Assume that there are n events e[1], e[2], ..., and e[n]. The types of events are user stake, /// user unstake, total stakes decrease and reward distribution. /// Right after event e[i], let the total pool stakes be s[i], the user pool stakes be u[i], /// the total stake decrease is d[i], and the rewards distributed be r[i]. /// /// The basic assumptions are, if /// + e[i] is user stake, r[i] = 0, u[i] > u[i-1] and s[i] - s[i-1] = u[i] - u[i-1]. /// + e[i] is user unstake, r[i] = 0, u[i] < u[i-1] and s[i] - s[i-1] = u[i] - u[i-1]. /// + e[i] is total stakes decrease, r[i] = 0, d[i] > 0, s[i] = s[i-1] - d[i] and u[i] = u[i-1] * (1 - d[i] / s[i-1]) /// + e[i] is reward distribution, r[i] > 0, u[i] = u[i-1] and s[i] = s[i-1]. /// /// So under the assumptions, if /// + e[i] is user stake/unstake, we can maintain the value of u[i] and s[i] easily. /// + e[i] is total stakes decrease, we can only maintain the value of s[i] easily. /// /// To compute the value of u[i], assuming the only events are total stakes decrease. Then after n events, /// u[n] = u[0] * (1 - d[1]/s[0]) * (1 - d[2]/s[1]) * ... * (1 - d[n]/s[n-1]) /// /// To compute the user stakes correctly, we can maintain the value of /// p[n] = (1 - d[1]/s[0]) * (1 - d[2]/s[1]) * ... * (1 - d[n]/s[n-1]) /// /// Then the user stakes from event x to event y is u[y] = u[x] * p[y] / p[x] /// /// As for the accumutated rewards, the total amount of rewards for the user is: /// u[0] u[1] u[n-1] /// g[n] = r[1] * ---- + r[2] * ---- + ... + r[n] * ------ /// s[0] s[1] s[n-1] /// /// Also, u[n] = u[0] * p[n], we have /// p[0] p[1] p[n-1] /// g[n] = u[0] * (r[1] * ---- + r[2] * ---- + ... + r[n] * ------) /// s[0] s[1] s[n-1] /// /// And, the rewards from event x to event y (both inclusive) for the user is: /// p[x-1] p[x] p[y-1] /// g[x->y] = u[x] * (r[x] * ------ + r[x+1] * ---- + ... + r[y] * ------) /// s[x-1] s[x] s[y-1] /// /// To check the accumulated total user rewards, we can maintain the value of /// p[0] p[1] p[n-1] /// acc = r[1] * ---- + r[2] * ---- + ... + r[n] * ------ /// s[0] s[1] s[n-1] /// /// For each event, if /// + e[i] is user stake or unstake, new accumulated rewards is /// gain += u[i-1] * (acc - last_user_acc) / last_user_prod, /// and update `last_user_acc` to `acc` /// and update `last_user_prod` to p[i]. /// + e[i] is total stakes decrease, p[i] *= (1 - d[i] / s[i-1]) /// + e[i] is reward distribution, acc += r[i] * p[i-1] / s[i-1]. /// /// Notice that total stakes decrease event will possible make s[i] be zero. We introduce epoch to handle this problem. /// When the total supply reduces to zero, we start a new epoch. /// /// Another problem is precision loss in solidity, the p[i] will eventually become a very small nonzero value. To solve /// the problem, we treat p[i] as m[i] * 10^{-18 - 9 * e[i]}, where m[i] is the magnitude and e[i] is the exponent. /// When the value of m[i] is smaller than 10^9, we will multiply m[i] by 1e9 and then increase e[i] by one. /// /// @dev The method comes from liquity's StabilityPool, the paper is in /// https://github.com/liquity/dev/blob/main/papers/Scalable_Reward_Distribution_with_Compounding_Stakes.pdf abstract contract MultipleRewardCompoundingAccumulator is ReentrancyGuardUpgradeable, LinearMultipleRewardDistributor, IMultipleRewardAccumulator { using SafeERC20Upgradeable for IERC20Upgradeable; using DecrementalFloatingPoint for uint112; /************* * Constants * *************/ /// @dev The precision used to calculate accumulated rewards. uint256 internal constant REWARD_PRECISION = 1e18; /// @dev Compiler will pack this into single `uint256`. struct RewardSnapshot { // The timestamp when the snapshot is updated. uint64 timestamp; // The reward integral until now. uint192 integral; } /// @dev Compiler will pack this into single `uint256`. struct ClaimData { // The number of pending rewards. uint128 pending; // The number of claimed rewards. uint128 claimed; } /// @dev Compiler will pack this into two `uint256`. struct UserRewardSnapshot { // The claim data for the user. ClaimData rewards; // The reward snapshot for user. RewardSnapshot checkpoint; } /************* * Variables * *************/ /// @inheritdoc IMultipleRewardAccumulator mapping(address => address) public override rewardReceiver; /// @notice Mapping from reward token address to global reward snapshot. /// /// - The inner mapping records the `acc` at different `(epoch, exponent)` /// - The outer mapping records the ((epoch, exponent) => acc) mappings, for different tokens. /// /// @dev The integral is defined as 1e18 * ∫(rate(t) * prod(t) / totalPoolShare(t) dt). mapping(address => mapping(uint256 => RewardSnapshot)) public epochToExponentToRewardSnapshot; /// @notice Mapping from user address to reward token address to user reward snapshot. /// /// @dev The integral is the value of `rewardSnapshot[token].integral` when the snapshot is taken. mapping(address => mapping(address => UserRewardSnapshot)) public userRewardSnapshot; /// @dev reserved slots. uint256[47] private __gap; /*************** * Constructor * ***************/ // solhint-disable-next-line func-name-mixedcase function __MultipleRewardCompoundingAccumulator_init() internal onlyInitializing { __LinearMultipleRewardDistributor_init(); } /************************* * Public View Functions * *************************/ /// @inheritdoc IMultipleRewardAccumulator function claimable(address _account, address _token) public view virtual override returns (uint256) { return _claimable(_account, _token); } /// @inheritdoc IMultipleRewardAccumulator function claimed(address _account, address _token) external view returns (uint256) { return userRewardSnapshot[_account][_token].rewards.claimed; } /**************************** * Public Mutated Functions * ****************************/ /// @inheritdoc IMultipleRewardAccumulator function setRewardReceiver(address _newReceiver) external { address _caller = _msgSender(); address _oldReceiver = rewardReceiver[_caller]; rewardReceiver[_caller] = _newReceiver; emit UpdateRewardReceiver(_caller, _oldReceiver, _newReceiver); } /// @inheritdoc IMultipleRewardAccumulator function checkpoint(address _account) external virtual override nonReentrant { _checkpoint(_account); } /// @inheritdoc IMultipleRewardAccumulator function claim() external override { address _sender = _msgSender(); claim(_sender, address(0)); } /// @inheritdoc IMultipleRewardAccumulator function claim(address _account) external override { claim(_account, address(0)); } /// @inheritdoc IMultipleRewardAccumulator function claim(address _account, address _receiver) public override nonReentrant { if (_account != _msgSender() && _receiver != address(0)) { revert ClaimOthersRewardToAnother(); } _checkpoint(_account); _claim(_account, _receiver); } /// @inheritdoc IMultipleRewardAccumulator function claimHistorical(address[] memory _tokens) external nonReentrant { address _sender = _msgSender(); _checkpoint(_sender); address _receiver = rewardReceiver[_sender]; if (_receiver == address(0)) _receiver = _sender; for (uint256 i = 0; i < _tokens.length; i++) { _claimSingle(_sender, _tokens[i], _receiver); } } /// @inheritdoc IMultipleRewardAccumulator function claimHistorical(address _account, address[] memory _tokens) external nonReentrant { _checkpoint(_account); address _receiver = rewardReceiver[_account]; if (_receiver == address(0)) _receiver = _account; for (uint256 i = 0; i < _tokens.length; i++) { _claimSingle(_account, _tokens[i], _receiver); } } /********************** * Internal Functions * **********************/ function _claimable(address _account, address _token) internal view virtual returns (uint256) { UserRewardSnapshot memory _userSnapshot = userRewardSnapshot[_account][_token]; (uint112 previousProd, uint256 shares) = _getUserPoolShare(_account); if (shares == 0) return _userSnapshot.rewards.pending; uint256 epochExponent = previousProd.epochAndExponent(); uint256 magnitude = previousProd.magnitude(); // Grab the sum 'S' from the epoch at which the stake was made. The gain may span up to one scale change. // If it does, the second portion of the gain is scaled by 1e9. // If the gain spans no scale change, the second portion will be 0. uint256 firstPortion = epochToExponentToRewardSnapshot[_token][epochExponent].integral - _userSnapshot.checkpoint.integral; uint256 secondPortion = epochToExponentToRewardSnapshot[_token][epochExponent + 1].integral / uint256(DecrementalFloatingPoint.HALF_PRECISION); return uint256(_userSnapshot.rewards.pending) + (shares * (firstPortion + secondPortion)) / (magnitude * REWARD_PRECISION); } /// @dev Internal function to update the global and user snapshot. /// /// @param _account The address of user to update. Use zero address /// if you only want to update global snapshot. function _checkpoint(address _account) internal virtual { _distributePendingReward(); if (_account != address(0)) { // checkpoint active reward tokens address[] memory _rewardTokens = getActiveRewardTokens(); for (uint256 i = 0; i < _rewardTokens.length; i++) { _updateSnapshot(_account, _rewardTokens[i]); } // checkpoint historical reward tokens _rewardTokens = getHistoricalRewardTokens(); for (uint256 i = 0; i < _rewardTokens.length; i++) { _updateSnapshot(_account, _rewardTokens[i]); } } } /// @notice Internal function to update snapshot for single token. /// @param _account The address of user to update. /// @param _token The address of token to update. function _updateSnapshot(address _account, address _token) internal virtual { UserRewardSnapshot memory _snapshot = userRewardSnapshot[_account][_token]; (uint112 currentProd, ) = _getTotalPoolShare(); uint48 epochExponent = currentProd.epochAndExponent(); _snapshot.rewards.pending = uint128(_claimable(_account, _token)); _snapshot.checkpoint = epochToExponentToRewardSnapshot[_token][epochExponent]; _snapshot.checkpoint.timestamp = uint64(block.timestamp); userRewardSnapshot[_account][_token] = _snapshot; } /// @dev Internal function to claim active reward tokens. /// /// @param _account The address of user to claim. /// @param _receiver The address of recipient of the reward token. function _claim(address _account, address _receiver) internal virtual { address _receiverStored = rewardReceiver[_account]; if (_receiverStored != address(0) && _receiver == address(0)) { _receiver = _receiverStored; } if (_receiver == address(0)) _receiver = _account; address[] memory _activeRewardTokens = getActiveRewardTokens(); for (uint256 i = 0; i < _activeRewardTokens.length; i++) { _claimSingle(_account, _activeRewardTokens[i], _receiver); } } /// @dev Internal function to claim single reward token. /// Caller should make sure `_checkpoint` is called before this function. /// /// @param _account The address of user to claim. /// @param _token The address of reward token. /// @param _receiver The address of recipient of the reward token. function _claimSingle( address _account, address _token, address _receiver ) internal virtual returns (uint256) { ClaimData memory _rewards = userRewardSnapshot[_account][_token].rewards; uint256 _amount = _rewards.pending; if (_amount > 0) { _rewards.claimed += _rewards.pending; _rewards.pending = 0; userRewardSnapshot[_account][_token].rewards = _rewards; IERC20Upgradeable(_token).safeTransfer(_receiver, _amount); emit Claim(_account, _token, _receiver, _amount); } return _amount; } /// @inheritdoc LinearMultipleRewardDistributor function _accumulateReward(address _token, uint256 _amount) internal virtual override { if (_amount == 0) return; (uint112 currentProd, uint256 totalShare) = _getTotalPoolShare(); if (totalShare == 0) { // no deposits, queue rewards rewardData[_token].queued += uint96(_amount); return; } uint48 epochExponent = currentProd.epochAndExponent(); uint256 magnitude = currentProd.magnitude(); RewardSnapshot memory _snapshot = epochToExponentToRewardSnapshot[_token][epochExponent]; _snapshot.timestamp = uint64(block.timestamp); // @note usually `_amount <= 10^6 * 10^18` and `magnitude <= 10^18`, // so the value of `_amount * REWARD_PRECISION` won't exceed type(uint192).max. // For the other parts, we rely on the overflow check provided by solc 0.8. _snapshot.integral += (uint192((_amount * REWARD_PRECISION) / totalShare) * uint192(magnitude)); epochToExponentToRewardSnapshot[_token][epochExponent] = _snapshot; } /// @dev Internal function to get the total pool shares. function _getTotalPoolShare() internal view virtual returns (uint112 currentProd, uint256 totalShare); /// @dev Internal function to get the amount of user shares. /// /// @param _account The address of user to query. function _getUserPoolShare(address _account) internal view virtual returns (uint112 previousProd, uint256 share); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IMultipleRewardDistributor { /********** * Events * **********/ /// @notice Emitted when new reward token is registered. /// /// @param token The address of reward token. /// @param distributor The address of reward distributor. event RegisterRewardToken(address indexed token, address indexed distributor); /// @notice Emitted when the reward distributor is updated. /// /// @param token The address of reward token. /// @param oldDistributor The address of previous reward distributor. /// @param newDistributor The address of current reward distributor. event UpdateRewardDistributor(address indexed token, address indexed oldDistributor, address indexed newDistributor); /// @notice Emitted when a reward token is unregistered. /// /// @param token The address of reward token. event UnregisterRewardToken(address indexed token); /// @notice Emitted when a reward token is deposited. /// /// @param token The address of reward token. /// @param amount The amount of reward token deposited. event DepositReward(address indexed token, uint256 amount); /********** * Errors * **********/ /// @dev Thrown when caller access an unactive reward token. error NotActiveRewardToken(); /// @dev Thrown when the address of reward distributor is `address(0)`. error RewardDistributorIsZero(); /// @dev Thrown when caller is not reward distributor. error NotRewardDistributor(); /// @dev Thrown when caller try to register an existing reward token. error DuplicatedRewardToken(); /// @dev Thrown when caller try to unregister a reward with pending rewards. error RewardDistributionNotFinished(); /************************* * Public View Functions * *************************/ /// @notice Return the address of reward distributor. /// /// @param token The address of reward token. function distributors(address token) external view returns (address); /// @notice Return the list of active reward tokens. function getActiveRewardTokens() external view returns (address[] memory); /// @notice Return the list of historical reward tokens. function getHistoricalRewardTokens() external view returns (address[] memory); /// @notice Return the amount of pending distributed rewards in current period. /// /// @param token The address of reward token. /// @return distributable The amount of reward token can be distributed in current period. /// @return undistributed The amount of reward token still locked in current period. function pendingRewards(address token) external view returns (uint256 distributable, uint256 undistributed); /**************************** * Public Mutated Functions * ****************************/ /// @notice Deposit new rewards to this contract. /// /// @param token The address of reward token. /// @param amount The amount of new rewards. function depositReward(address token, uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable-v4/access/AccessControlUpgradeable.sol"; import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable-v4/token/ERC20/IERC20Upgradeable.sol"; import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable-v4/token/ERC20/utils/SafeERC20Upgradeable.sol"; import { EnumerableSetUpgradeable } from "@openzeppelin/contracts-upgradeable-v4/utils/structs/EnumerableSetUpgradeable.sol"; import { IMultipleRewardDistributor } from "./IMultipleRewardDistributor.sol"; import { LinearReward } from "./LinearReward.sol"; // solhint-disable no-empty-blocks // solhint-disable not-rely-on-time abstract contract LinearMultipleRewardDistributor is AccessControlUpgradeable, IMultipleRewardDistributor { using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; using SafeERC20Upgradeable for IERC20Upgradeable; using LinearReward for LinearReward.RewardData; /************* * Constants * *************/ /// @notice The role used to manage rewards. bytes32 public constant REWARD_MANAGER_ROLE = keccak256("REWARD_MANAGER_ROLE"); /// @notice The length of reward period in seconds. /// @dev If the value is zero, the reward will be distributed immediately. /// @dev It is either zero or at least 1 day (which is 86400). uint40 public immutable periodLength; /************* * Variables * *************/ /// @inheritdoc IMultipleRewardDistributor mapping(address => address) public override distributors; /// @notice Mapping from reward token address to linear distribution reward data. mapping(address => LinearReward.RewardData) public rewardData; /// @dev The list of active reward tokens. EnumerableSetUpgradeable.AddressSet internal activeRewardTokens; /// @dev The list of historical reward tokens. EnumerableSetUpgradeable.AddressSet private historicalRewardTokens; /// @dev reserved slots. uint256[46] private __gap; /*************** * Constructor * ***************/ constructor(uint40 _periodLength) { require(_periodLength == 0 || (_periodLength >= 1 days && _periodLength <= 28 days), "invalid period length"); periodLength = _periodLength; } // solhint-disable-next-line func-name-mixedcase function __LinearMultipleRewardDistributor_init() internal onlyInitializing {} /************************* * Public View Functions * *************************/ /// @inheritdoc IMultipleRewardDistributor function getActiveRewardTokens() public view override returns (address[] memory _rewardTokens) { uint256 _length = activeRewardTokens.length(); _rewardTokens = new address[](_length); for (uint256 i = 0; i < _length; i++) { _rewardTokens[i] = activeRewardTokens.at(i); } } /// @inheritdoc IMultipleRewardDistributor function getHistoricalRewardTokens() public view override returns (address[] memory _rewardTokens) { uint256 _length = historicalRewardTokens.length(); _rewardTokens = new address[](_length); for (uint256 i = 0; i < _length; i++) { _rewardTokens[i] = historicalRewardTokens.at(i); } } /// @inheritdoc IMultipleRewardDistributor function pendingRewards(address _token) external view override returns (uint256, uint256) { return rewardData[_token].pending(); } /**************************** * Public Mutated Functions * ****************************/ /// @inheritdoc IMultipleRewardDistributor function depositReward(address _token, uint256 _amount) external override { address _distributor = _msgSender(); if (!activeRewardTokens.contains(_token)) revert NotActiveRewardToken(); if (distributors[_token] != _distributor) revert NotRewardDistributor(); if (_amount > 0) { IERC20Upgradeable(_token).safeTransferFrom(_distributor, address(this), _amount); } _distributePendingReward(); _notifyReward(_token, _amount); emit DepositReward(_token, _amount); } /************************ * Restricted Functions * ************************/ /// @notice Register a new reward token. /// @dev Make sure no fee on transfer token is added as reward token. /// /// @param _token The address of reward token. /// @param _distributor The address of reward distributor. function registerRewardToken(address _token, address _distributor) external onlyRole(REWARD_MANAGER_ROLE) { if (_distributor == address(0)) revert RewardDistributorIsZero(); if (activeRewardTokens.contains(_token)) revert DuplicatedRewardToken(); activeRewardTokens.add(_token); distributors[_token] = _distributor; historicalRewardTokens.remove(_token); emit RegisterRewardToken(_token, _distributor); } /// @notice Update the distributor for reward token. /// /// @param _token The address of reward token. /// @param _newDistributor The address of new reward distributor. function updateRewardDistributor(address _token, address _newDistributor) external onlyRole(REWARD_MANAGER_ROLE) { if (_newDistributor == address(0)) revert RewardDistributorIsZero(); if (!activeRewardTokens.contains(_token)) revert NotActiveRewardToken(); address _oldDistributor = distributors[_token]; distributors[_token] = _newDistributor; emit UpdateRewardDistributor(_token, _oldDistributor, _newDistributor); } /// @notice Unregister an existing reward token. /// /// @param _token The address of reward token. function unregisterRewardToken(address _token) external onlyRole(REWARD_MANAGER_ROLE) { if (!activeRewardTokens.contains(_token)) revert NotActiveRewardToken(); LinearReward.RewardData memory _data = rewardData[_token]; unchecked { (uint256 _distributable, uint256 _undistributed) = _data.pending(); if (_data.queued < periodLength) _data.queued = 0; // ignore round error if (_data.queued + _distributable + _undistributed > 0) revert RewardDistributionNotFinished(); } activeRewardTokens.remove(_token); distributors[_token] = address(0); historicalRewardTokens.add(_token); emit UnregisterRewardToken(_token); } /********************** * Internal Functions * **********************/ /// @dev Internal function to notify new rewards. /// /// @param _token The address of token. /// @param _amount The amount of new rewards. function _notifyReward(address _token, uint256 _amount) internal { if (periodLength == 0) { _accumulateReward(_token, _amount); } else { LinearReward.RewardData memory _data = rewardData[_token]; _data.increase(periodLength, _amount); rewardData[_token] = _data; } } /// @dev Internal function to distribute all pending reward tokens. function _distributePendingReward() internal { if (periodLength == 0 || activeRewardTokens.length() == 0) return; address[] memory _activeRewardTokens = getActiveRewardTokens(); for (uint256 i = 0; i < _activeRewardTokens.length; i++) { address _token = _activeRewardTokens[i]; (uint256 _pending, ) = rewardData[_token].pending(); rewardData[_token].lastUpdate = uint40(block.timestamp); if (_pending > 0) { _accumulateReward(_token, _pending); } } } /// @dev Internal function to accumulate distributed rewards. /// /// @param _token The address of token. /// @param _amount The amount of rewards to accumulate. function _accumulateReward(address _token, uint256 _amount) internal virtual; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { SafeCastUpgradeable } from "@openzeppelin/contracts-upgradeable-v4/utils/math/SafeCastUpgradeable.sol"; // solhint-disable not-rely-on-time library LinearReward { using SafeCastUpgradeable for uint256; /// @dev Compiler will pack this into single `uint256`. /// Usually, we assume the amount of rewards won't exceed `uint96.max`. /// In such case, the rate won't exceed `uint80.max`, since `periodLength` is at least `86400`. /// Also `uint40.max` is enough for timestamp, which is about 30000 years. struct RewardData { // The amount of rewards pending to distribute. uint96 queued; // The current reward rate per second. uint80 rate; // The last timestamp when the reward is distributed. uint40 lastUpdate; // The timestamp when this period will finish. uint40 finishAt; } /// @dev Add new rewards to current one. It is possible that the rewards will not distribute immediately. /// The rewards will be only distributed when current period is end or the current increase or /// decrease no more than 10%. /// /// @param _data The struct of reward data, will be modified inplace. /// @param _periodLength The length of a period, caller should make sure it is at least `86400`. /// @param _amount The amount of new rewards to distribute. function increase( RewardData memory _data, uint256 _periodLength, uint256 _amount ) internal view { _amount = _amount + _data.queued; _data.queued = 0; if (block.timestamp >= _data.finishAt) { // period finished, distribute to next period _data.rate = (_amount / _periodLength).toUint80(); _data.queued = uint96(_amount - (_data.rate * _periodLength)); // keep rounding error _data.lastUpdate = uint40(block.timestamp); _data.finishAt = uint40(block.timestamp + _periodLength); } else { uint256 _elapsed = block.timestamp - (_data.finishAt - _periodLength); uint256 _distributed = uint256(_data.rate) * _elapsed; if (_distributed * 9 <= _amount * 10) { // APR increase or drop no more than 10%, distribute _amount = _amount + uint256(_data.rate) * (_data.finishAt - _data.lastUpdate); _data.rate = (_amount / _periodLength).toUint80(); _data.queued = uint96(_amount - (_data.rate * _periodLength)); // keep rounding error _data.lastUpdate = uint40(block.timestamp); _data.finishAt = uint40(block.timestamp + _periodLength); _data.lastUpdate = uint40(block.timestamp); } else { // APR drop more than 10%, wait for more rewards _data.queued = _amount.toUint96(); } } } /// @dev Return the amount of pending distributed rewards in current period. /// /// @param _data The struct of reward data. function pending(RewardData memory _data) internal view returns (uint256, uint256) { uint256 _elapsed; uint256 _left; if (block.timestamp > _data.finishAt) { // finishAt >= lastUpdate will happen, if `_notifyReward` is not called during current period. _elapsed = _data.finishAt >= _data.lastUpdate ? _data.finishAt - _data.lastUpdate : 0; } else { unchecked { _elapsed = block.timestamp - _data.lastUpdate; _left = uint256(_data.finishAt) - block.timestamp; } } return (uint256(_data.rate) * _elapsed, uint256(_data.rate) * _left); } }
// SPDX-License-Identifier: MIT pragma solidity =0.8.20; import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable-v4/access/AccessControlUpgradeable.sol"; import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable-v4/token/ERC20/IERC20Upgradeable.sol"; import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable-v4/token/ERC20/utils/SafeERC20Upgradeable.sol"; import { DecrementalFloatingPoint } from "../../common/math/DecrementalFloatingPoint.sol"; import { IMultipleRewardAccumulator } from "../../common/rewards/accumulator/IMultipleRewardAccumulator.sol"; import { MultipleRewardCompoundingAccumulator } from "../../common/rewards/accumulator/MultipleRewardCompoundingAccumulator.sol"; import { LinearMultipleRewardDistributor } from "../../common/rewards/distributor/LinearMultipleRewardDistributor.sol"; import { IFxBoostableRebalancePool } from "../../interfaces/f(x)/IFxBoostableRebalancePool.sol"; import { IFxMarket } from "../../interfaces/f(x)/IFxMarket.sol"; import { IFxShareableRebalancePool } from "../../interfaces/f(x)/IFxShareableRebalancePool.sol"; import { IFxTokenWrapper } from "../../interfaces/f(x)/IFxTokenWrapper.sol"; import { IFxTreasury } from "../../interfaces/f(x)/IFxTreasury.sol"; import { IVotingEscrow } from "../../interfaces/voting-escrow/IVotingEscrow.sol"; import { IVotingEscrowHelper } from "../../interfaces/voting-escrow/IVotingEscrowHelper.sol"; import { ICurveTokenMinter } from "../../interfaces/ICurveTokenMinter.sol"; // solhint-disable not-rely-on-time /// @title ShareableRebalancePool /// @notice To add boost for FXN, we maintain a time-weighted boost ratio for each user. /// boost[u][i] = min(balance[u][i], 0.4 * balance[u][i] + ve[u][i] * totalSupply[i] / veTotal[i] * 0.6) /// ratio[u][x -> y] = sum(boost[u][i] / balance[u][i] * (t[i] - t[i - 1])) / (t[y] - t[x]) /// /// 1. supply[w] is the total amount of token staked at the beginning of week `w`. /// 2. veSupply[w] is the total ve supply at the beginning of week `w`. /// 3. ve[u][w] is the ve balance for user `u` at the beginning of week `w`. /// 4. balance[u][w] is the amount of token staked for user `u` at the beginning of week `w`. contract ShareableRebalancePool is MultipleRewardCompoundingAccumulator, IFxShareableRebalancePool { using SafeERC20Upgradeable for IERC20Upgradeable; using DecrementalFloatingPoint for uint112; /************* * Constants * *************/ /// @notice The role for liquidator. bytes32 public constant LIQUIDATOR_ROLE = keccak256("LIQUIDATOR_ROLE"); /// @notice The role for ve balance sharing. bytes32 public constant VE_SHARING_ROLE = keccak256("VE_SHARING_ROLE"); /// @notice The role for ve balance sharing. bytes32 public constant WITHDRAW_FROM_ROLE = keccak256("WITHDRAW_FROM_ROLE"); /// @dev The precison use to calculation. uint256 private constant PRECISION = 1e18; /// @dev The number of seconds in one day. uint256 private constant DAY = 1 days; /// @dev The number of seconds in one week. uint256 private constant WEEK = 7 days; /// @notice The address of FXN token. address public immutable fxn; /// @notice The address of Voting Escrow FXN. address public immutable ve; /// @notice The address of VotingEscrowHelper contract. address public immutable veHelper; /// @notice The address of FXN token minter. address public immutable minter; /*********** * Structs * ***********/ /// @dev The token balance struct. The compiler will pack this into single `uint256`. /// /// @param product The encoding product data, see the comments of `DecrementalFloatingPoint`. /// @param amount The amount of token currently. /// @param updateAt The timestamp in day when the struct is updated. struct TokenBalance { uint112 product; uint104 amount; uint40 updateAt; } /// @dev The gauge data struct. The compiler will pack this into single `uint256`. /// /// @param gauge The address of the gauge. /// @param claimAt The timestamp in second when last claim happened. struct Gauge { address gauge; uint64 claimAt; } /// @dev The boost checkpoint struct. The compiler will pack this into single `uint256`. /// Each epoch `t` starts at timestamp `t * 86400 * 7` (inclusive) and ends at `(t + 1) * 86400 * 7` (not inclusive). /// /// @param boostRatio The boost ratio of current epoch. /// @param historyIndex The index of supply in totalSupplyHistory at checkpoint. struct BoostCheckpoint { uint64 boostRatio; uint64 historyIndex; } /************* * Variables * *************/ /// @inheritdoc IFxBoostableRebalancePool address public treasury; /// @inheritdoc IFxBoostableRebalancePool address public market; /// @notice The gauge struct. Gauge public gauge; /// @inheritdoc IFxBoostableRebalancePool address public override baseToken; /// @inheritdoc IFxBoostableRebalancePool address public override asset; /// @dev The TokenBalance struct for current total supply. TokenBalance private _totalSupply; /// @dev Mapping account address to TokenBalance struct. mapping(address => TokenBalance) private _balances; /// @dev It was used as the boostCheckpoint in previous version, now is deprecated. mapping(address => bytes32) private _deprecated_boostCheckpoint; /// @notice The number of total supply history. uint256 public numTotalSupplyHistory; /// @notice Mapping from index to history totalSupply. /// /// If there are multiple updates at the same timestamp, only the last one will be recorded. mapping(uint256 => TokenBalance) public totalSupplyHistory; /// @notice The maximum collateral ratio to call liquidate. uint256 public liquidatableCollateralRatio; /// @notice The address of token wrapper for liquidated base token; address public wrapper; /// @notice Error trackers for the error correction in the loss calculation. uint256 public lastAssetLossError; /// @notice Mapping from account address to index in `totalSupplyHistory`. mapping(address => BoostCheckpoint) public boostCheckpoint; /// @notice Mapping from vote owner address to current balance sum of accepted stakers. mapping(address => TokenBalance) public voteOwnerBalances; /// @notice Mapping from vote owner address to week timestamp to historical balance sum of accepted stakers. mapping(address => mapping(uint256 => uint256)) public voteOwnerHistoryBalances; /// @notice Mapping from owner address to staker address to the vote sharing status. mapping(address => mapping(address => bool)) public isStakerAllowed; /// @inheritdoc IFxShareableRebalancePool mapping(address => address) public getStakerVoteOwner; /*************** * Constructor * ***************/ constructor( address _fxn, address _ve, address _veHelper, address _minter ) LinearMultipleRewardDistributor(1 weeks) { fxn = _fxn; ve = _ve; veHelper = _veHelper; minter = _minter; } function initialize( address _treasury, address _market, address _gauge ) external initializer { // __Context_init(); // from ContextUpgradeable, comment out to reduce codesize // __ERC165_init(); // from ERC165Upgradeable, comment out to reduce codesize // __AccessControl_init(); // from AccessControlUpgradeable, comment out to reduce codesize __ReentrancyGuard_init(); // from ReentrancyGuardUpgradeable __MultipleRewardCompoundingAccumulator_init(); // from MultipleRewardCompoundingAccumulator // access control AccessControlUpgradeable._grantRole(DEFAULT_ADMIN_ROLE, _msgSender()); AccessControlUpgradeable._grantRole(REWARD_MANAGER_ROLE, _msgSender()); treasury = _treasury; market = _market; gauge.gauge = _gauge; baseToken = IFxTreasury(_treasury).baseToken(); asset = IFxTreasury(_treasury).fToken(); wrapper = address(this); _totalSupply.product = DecrementalFloatingPoint.encode(0, 0, uint64(PRECISION)); _totalSupply.updateAt = uint40(block.timestamp); totalSupplyHistory[0] = _totalSupply; numTotalSupplyHistory = 1; } /************************* * Public View Functions * *************************/ /// @inheritdoc IFxBoostableRebalancePool function totalSupply() external view returns (uint256) { return _totalSupply.amount; } /// @inheritdoc IFxBoostableRebalancePool function balanceOf(address _account) public view override returns (uint256) { TokenBalance memory _balance = _balances[_account]; return _getCompoundedBalance(_balance.amount, _balance.product, _totalSupply.product); } /// @inheritdoc IFxBoostableRebalancePool function getBoostRatio(address _account) public view returns (uint256) { return _getBoostRatio(_account); } /// @inheritdoc IMultipleRewardAccumulator function claimable(address _account, address _token) public view virtual override returns (uint256) { if (_token == fxn) { uint256 _pending = userRewardSnapshot[_account][_token].rewards.pending; uint256 fullEarned = _claimable(_account, _token) - _pending; uint256 ratio = getBoostRatio(_account); uint256 boostEarned = (fullEarned * ratio) / PRECISION; return _pending + boostEarned; } else { return _claimable(_account, _token); } } /**************************** * Public Mutated Functions * ****************************/ /// @inheritdoc IFxBoostableRebalancePool function deposit(uint256 _amount, address _receiver) external override { if (hasRole(VE_SHARING_ROLE, _receiver)) revert ErrorVoteOwnerCannotStake(); address _sender = _msgSender(); // transfer asset token to this contract address _asset = asset; if (_amount == type(uint256).max) { _amount = IERC20Upgradeable(_asset).balanceOf(_sender); } if (_amount == 0) revert DepositZeroAmount(); IERC20Upgradeable(_asset).safeTransferFrom(_sender, address(this), _amount); // @note after checkpoint, the account balances are correct, we can `_balances` safely. _checkpoint(_receiver); // It should never exceed `type(uint104).max`. TokenBalance memory _supply = _totalSupply; TokenBalance memory _balance = _balances[_receiver]; TokenBalance memory _ownerBalance; _supply.amount += uint104(_amount); _supply.updateAt = uint40(block.timestamp); _balance.amount += uint104(_amount); // @note after checkpoint, the voteOwnerBalances are correct. address _owner = getStakerVoteOwner[_receiver]; if (_owner != address(0)) { _ownerBalance = voteOwnerBalances[_owner]; _ownerBalance.amount += uint104(_amount); } // this is already updated in `_checkpoint(_receiver)`. // _balance.updateAt = uint40(block.timestamp); // _ownerBalance.updateAt = uint40(block.timestamp); _recordTotalSupply(_supply); _balances[_receiver] = _balance; // update boost checkpoint at last _updateBoostCheckpoint(_receiver, _owner, _balance, _ownerBalance, _supply); emit Deposit(_sender, _receiver, _amount); emit UserDepositChange(_receiver, _balance.amount, 0); } /// @inheritdoc IFxBoostableRebalancePool function withdraw(uint256 _amount, address _receiver) external virtual override { _withdraw(_msgSender(), _amount, _receiver); } /// @inheritdoc IFxShareableRebalancePool function withdrawFrom( address _owner, uint256 _amount, address _receiver ) external override onlyRole(WITHDRAW_FROM_ROLE) { _withdraw(_owner, _amount, _receiver); } /// @inheritdoc IFxBoostableRebalancePool function liquidate(uint256 _maxAmount, uint256 _minBaseOut) external virtual override onlyRole(LIQUIDATOR_ROLE) returns (uint256 _liquidated, uint256 _baseOut) { _checkpoint(address(0)); IFxTreasury _treasury = IFxTreasury(treasury); if (_treasury.collateralRatio() >= liquidatableCollateralRatio) { revert CannotLiquidate(); } (, uint256 _maxLiquidatable) = _treasury.maxRedeemableFToken(liquidatableCollateralRatio); uint256 _amount = _maxLiquidatable; if (_amount > _maxAmount) { _amount = _maxAmount; } address _asset = asset; address _market = market; address _wrapper = wrapper; _liquidated = IERC20Upgradeable(_asset).balanceOf(address(this)); if (_amount > _liquidated) { // cannot liquidate more than assets in this contract. _amount = _liquidated; } IERC20Upgradeable(_asset).safeApprove(_market, 0); IERC20Upgradeable(_asset).safeApprove(_market, _amount); (_baseOut, ) = IFxMarket(_market).redeem(_amount, 0, _wrapper, _minBaseOut); _liquidated = _liquidated - IERC20Upgradeable(_asset).balanceOf(address(this)); emit Liquidate(_liquidated, _baseOut); // wrap base token if needed address _token = baseToken; if (_wrapper != address(this)) { _baseOut = IFxTokenWrapper(_wrapper).wrap(_baseOut); _token = IFxTokenWrapper(_wrapper).dst(); } // distribute liquidated base token _accumulateReward(_token, _baseOut); // notify loss _notifyLoss(_liquidated); } /// @inheritdoc IFxShareableRebalancePool function toggleVoteSharing(address _staker) external override onlyRole(VE_SHARING_ROLE) { address _owner = _msgSender(); if (_staker == _owner) { revert ErrorSelfSharingIsNotAllowed(); } if (getStakerVoteOwner[_owner] != address(0)) { revert ErrorCascadedSharingIsNotAllowed(); } if (isStakerAllowed[_owner][_staker]) { isStakerAllowed[_owner][_staker] = false; emit CancelShareVote(_owner, _staker); } else { isStakerAllowed[_owner][_staker] = true; emit ShareVote(_owner, _staker); } if (getStakerVoteOwner[_staker] == _owner) { _revokeVoteSharing(_owner, _staker); } } /// @inheritdoc IFxShareableRebalancePool function acceptSharedVote(address _newOwner) external override { address _staker = _msgSender(); if (!isStakerAllowed[_newOwner][_staker]) { revert ErrorVoteShareNotAllowed(); } address _oldOwner = getStakerVoteOwner[_staker]; if (_oldOwner == _newOwner) revert ErrorRepeatAcceptSharedVote(); if (_oldOwner != address(0)) { _revokeVoteSharing(_oldOwner, _staker); } else { // @note after checkpoint, the epoch of `_balances[_staker]` and `voteOwnerBalances[_oldOwner]` // are on the latest epoch, we can safely to do add or subtract. _checkpoint(_staker); } getStakerVoteOwner[_staker] = _newOwner; // update boost ratio for staker. TokenBalance memory _balance = _balances[_staker]; TokenBalance memory _supply = _totalSupply; TokenBalance memory _ownerBalance = _updateVoteOwnerBalance(_newOwner, _supply); _ownerBalance.amount += _balance.amount; _updateBoostCheckpoint(_staker, _newOwner, _balance, _ownerBalance, _supply); emit AcceptSharedVote(_staker, address(0), _newOwner); } /// @inheritdoc IFxShareableRebalancePool function rejectSharedVote() external override { address _staker = _msgSender(); address _owner = getStakerVoteOwner[_staker]; if (_owner == address(0)) revert ErrorNoAcceptedSharedVote(); _revokeVoteSharing(_owner, _staker); } /************************ * Restricted Functions * ************************/ /// @notice Update the address of reward wrapper. /// @param _newWrapper The new address of reward wrapper. function updateWrapper(address _newWrapper) external onlyRole(DEFAULT_ADMIN_ROLE) { if (IFxTokenWrapper(_newWrapper).src() != baseToken) { revert ErrorWrapperSrcMismatch(); } address _oldWrapper = wrapper; if (_oldWrapper != address(this) && IFxTokenWrapper(_oldWrapper).dst() != IFxTokenWrapper(_newWrapper).dst()) { revert ErrorWrapperDstMismatch(); } wrapper = _newWrapper; emit UpdateWrapper(_oldWrapper, _newWrapper); } /// @notice Update the collateral ratio line for liquidation. /// @param _newRatio The new liquidatable collateral ratio. function updateLiquidatableCollateralRatio(uint256 _newRatio) external onlyRole(DEFAULT_ADMIN_ROLE) { uint256 _oldRatio = liquidatableCollateralRatio; liquidatableCollateralRatio = _newRatio; emit UpdateLiquidatableCollateralRatio(_oldRatio, _newRatio); } /********************** * Internal Functions * **********************/ /// @inheritdoc AccessControlUpgradeable function _grantRole(bytes32 _role, address _account) internal virtual override { if (_role == VE_SHARING_ROLE && _balances[_account].amount > 0) { revert ErrorVoteOwnerCannotStake(); } AccessControlUpgradeable._grantRole(_role, _account); } /// @inheritdoc MultipleRewardCompoundingAccumulator function _checkpoint(address _account) internal virtual override { // fetch FXN from gauge every 24h if (gauge.gauge != address(0) && block.timestamp > uint256(gauge.claimAt) + DAY) { uint256 _balance = IERC20Upgradeable(fxn).balanceOf(address(this)); ICurveTokenMinter(minter).mint(gauge.gauge); uint256 _minted = IERC20Upgradeable(fxn).balanceOf(address(this)) - _balance; gauge.claimAt = uint64(block.timestamp); _notifyReward(fxn, _minted); } address _owner = getStakerVoteOwner[_account]; if (_account != address(0)) { IVotingEscrowHelper(veHelper).checkpoint(_owner == address(0) ? _account : _owner); } MultipleRewardCompoundingAccumulator._checkpoint(_account); if (_account != address(0)) { TokenBalance memory _supply = _totalSupply; TokenBalance memory _balance = _updateUserBalance(_account, _supply); TokenBalance memory _ownerBalance = _updateVoteOwnerBalance(_owner, _supply); _updateBoostCheckpoint(_account, _owner, _balance, _ownerBalance, _supply); } } /// @inheritdoc MultipleRewardCompoundingAccumulator function _updateSnapshot(address _account, address _token) internal virtual override { UserRewardSnapshot memory _snapshot = userRewardSnapshot[_account][_token]; uint48 epochExponent = _totalSupply.product.epochAndExponent(); if (_token == fxn) { // update `voteOwnerBalance` here, since it is needed in `_getBoostRatio` _updateVoteOwnerBalance(getStakerVoteOwner[_account], _totalSupply); unchecked { uint256 fullEarned = _claimable(_account, _token) - _snapshot.rewards.pending; // save gas when on earned if (fullEarned > 0) { uint256 ratio = _getBoostRatio(_account); uint256 boostEarned = (fullEarned * ratio) / PRECISION; _snapshot.rewards.pending += uint128(boostEarned); if (fullEarned > boostEarned) { // redistribute unboosted rewards. _notifyReward(fxn, fullEarned - boostEarned); } } } } else { _snapshot.rewards.pending = uint128(_claimable(_account, _token)); } _snapshot.checkpoint = epochToExponentToRewardSnapshot[_token][epochExponent]; _snapshot.checkpoint.timestamp = uint64(block.timestamp); userRewardSnapshot[_account][_token] = _snapshot; } /// @inheritdoc MultipleRewardCompoundingAccumulator function _getTotalPoolShare() internal view virtual override returns (uint112 _currentProd, uint256 _totalShare) { TokenBalance memory _supply = _totalSupply; _currentProd = _supply.product; _totalShare = _supply.amount; } /// @inheritdoc MultipleRewardCompoundingAccumulator function _getUserPoolShare(address _account) internal view virtual override returns (uint112 _previousProd, uint256 _share) { TokenBalance memory _balance = _balances[_account]; _previousProd = _balance.product; _share = _balance.amount; } /// @dev Internal function to withdraw assets from this contract. /// @param _sender The address of owner to withdraw from. /// @param _amount The amount of token to withdraw. /// @param _receiver The address of token receiver. function _withdraw( address _sender, uint256 _amount, address _receiver ) internal { // @note after checkpoint, the account balances are correct, we can `_balances` safely. _checkpoint(_sender); TokenBalance memory _supply = _totalSupply; TokenBalance memory _balance = _balances[_sender]; TokenBalance memory _ownerBalance; if (_amount > _balance.amount) _amount = _balance.amount; if (_amount == 0) revert WithdrawZeroAmount(); unchecked { _supply.amount -= uint104(_amount); _supply.updateAt = uint40(block.timestamp); _balance.amount -= uint104(_amount); } // @note after checkpoint, the voteOwnerBalances are correct. address _owner = getStakerVoteOwner[_sender]; if (_owner != address(0)) { _ownerBalance = voteOwnerBalances[_owner]; _ownerBalance.amount -= uint104(_amount); } // this is already updated in `_checkpoint(_sender)`. // _balance.updateAt = uint40(block.timestamp); // _ownerBalance.updateAt = uint40(block.timestamp); _recordTotalSupply(_supply); _balances[_sender] = _balance; // update boost checkpoint at last _updateBoostCheckpoint(_sender, _owner, _balance, _ownerBalance, _supply); IERC20Upgradeable(asset).safeTransfer(_receiver, _amount); emit Withdraw(_sender, _receiver, _amount); emit UserDepositChange(_sender, _balance.amount, 0); } /// @dev Internal function to revoke vote sharing. /// @param _owner The address of vote owner. /// @param _staker The address of staker to revoke. function _revokeVoteSharing(address _owner, address _staker) internal { // @note after checkpoint, the epoch of `_balances[_staker]` and `voteOwnerBalances[_oldOwner]` // are on the latest epoch, we can safely to do add or subtract. _checkpoint(_staker); TokenBalance memory _balance = _balances[_staker]; TokenBalance memory _ownerBalance = voteOwnerBalances[_owner]; // no uncheck here, just in case _ownerBalance.amount -= _balance.amount; voteOwnerBalances[_owner] = _ownerBalance; getStakerVoteOwner[_staker] = address(0); // @note it is ok to pass a random `_ownerBalance` to this function _updateBoostCheckpoint(_staker, address(0), _balance, _ownerBalance, _totalSupply); emit AcceptSharedVote(_staker, _owner, address(0)); } /// @dev Internal function to update the balance of vote owner. /// @param _owner The address of vote owner. /// @param _supply The latest total supply struct. /// @return _balance The updated token balance for vote owner. function _updateVoteOwnerBalance(address _owner, TokenBalance memory _supply) internal virtual returns (TokenBalance memory _balance) { // update `voteOwnerBalances[_owner]` to latest epoch and record history value if (_owner == address(0)) return _balance; _balance = voteOwnerBalances[_owner]; // it happens the owner has no update before if (_balance.updateAt == 0) _balance.updateAt = uint40(block.timestamp); uint256 prevWeekTs = _getWeekTs(_balance.updateAt); _balance.amount = uint104(_getCompoundedBalance(_balance.amount, _balance.product, _supply.product)); _balance.product = _supply.product; _balance.updateAt = uint40(block.timestamp); // @note since it will be updated in `_updateBoostCheckpoint`, we don't need to update it now. // voteOwnerBalances[_owner] = _balance; // @note Normally, `prevWeekTs` equals to `nextWeekTs` so we will only sstore 1 time in most of the time. // // When `prevWeekTs < nextWeekTs`, there are some extreme situation that liquidation happens between // `_ownerBalance.updateAt` and `prevWeekTs`, also some time between `prevWeekTs` and `block.timestamp`. // Then we cannot calculate the amount at `prevWeekTs` correctly. Since the situation rarely happens, // it is ok to use `_ownerBalance.amount` only. uint256 nextWeekTs = _getWeekTs(block.timestamp); while (prevWeekTs < nextWeekTs) { voteOwnerHistoryBalances[_owner][prevWeekTs] = _balance.amount; prevWeekTs += WEEK; } } /// @dev Internal function to update the balance of user. /// @param _account The address of user to update. /// @param _supply The latest total supply struct. /// @return _balance The updated token balance for the user. function _updateUserBalance(address _account, TokenBalance memory _supply) internal virtual returns (TokenBalance memory _balance) { _balance = _balances[_account]; uint104 _newBalance = uint104(_getCompoundedBalance(_balance.amount, _balance.product, _supply.product)); if (_newBalance != _balance.amount) { // no unchecked here, just in case emit UserDepositChange(_account, _newBalance, _balance.amount - _newBalance); } _balance.amount = _newBalance; _balance.product = _supply.product; _balance.updateAt = uint40(block.timestamp); _balances[_account] = _balance; } /// @dev Internal function update boost checkpoint for the user. /// @param _account The address of user to update. /// @param _balance The latest balance struct of the user. /// @param _supply The latest total supply struct. function _updateBoostCheckpoint( address _account, address _owner, TokenBalance memory _balance, TokenBalance memory _ownerBalance, TokenBalance memory _supply ) internal { if (_owner == address(0)) { _ownerBalance = _balance; _owner = _account; } else { voteOwnerBalances[_owner] = _ownerBalance; uint256 nextWeekTs = _getWeekTs(block.timestamp); voteOwnerHistoryBalances[_owner][nextWeekTs] = _ownerBalance.amount; } uint256 _ratio = _computeBoostRatio( _ownerBalance.amount, _balance.amount, _supply.amount, IVotingEscrow(ve).balanceOf(_owner), IVotingEscrow(ve).totalSupply() ); unchecked { boostCheckpoint[_account] = BoostCheckpoint(uint64(_ratio), uint64(numTotalSupplyHistory - 1)); } } /// @dev Internal function to reduce asset loss due to liquidation. /// @param _loss The amount of asset used by liquidation. function _notifyLoss(uint256 _loss) internal { TokenBalance memory _supply = _totalSupply; uint256 _assetLossPerUnitStaked; // use >= here, in case someone send extra asset to this contract. if (_loss >= _supply.amount) { // all assets are liquidated. _assetLossPerUnitStaked = PRECISION; lastAssetLossError = 0; _supply.amount = 0; } else { uint256 _lossNumerator = _loss * PRECISION - lastAssetLossError; // Add 1 to make error in quotient positive. We want "slightly too much" LUSD loss, // which ensures the error in any given compoundedAssetDeposit favors the Stability Pool. _assetLossPerUnitStaked = (_lossNumerator / uint256(_supply.amount)) + 1; lastAssetLossError = _assetLossPerUnitStaked * uint256(_supply.amount) - _lossNumerator; _supply.amount -= uint104(_loss); } // The newProductFactor is the factor by which to change all deposits, due to the depletion of Stability Pool LUSD in the liquidation. // We make the product factor 0 if there was a pool-emptying. Otherwise, it is (1 - LUSDLossPerUnitStaked) uint256 _newProductFactor = PRECISION - _assetLossPerUnitStaked; _supply.product = _supply.product.mul(uint64(_newProductFactor)); _supply.updateAt = uint40(block.timestamp); _recordTotalSupply(_supply); } /// @dev Internal function to record the historical total supply. /// @param _supply The new total supply to record. function _recordTotalSupply(TokenBalance memory _supply) internal { unchecked { uint256 _numTotalSupplyHistory = numTotalSupplyHistory; if (totalSupplyHistory[_numTotalSupplyHistory - 1].updateAt == _supply.updateAt) { totalSupplyHistory[_numTotalSupplyHistory - 1] = _supply; } else { totalSupplyHistory[_numTotalSupplyHistory] = _supply; numTotalSupplyHistory = _numTotalSupplyHistory + 1; } _totalSupply = _supply; } } /// @dev Internal function to compute the amount of asset deposited after several liquidation. /// /// @param _initialBalance The amount of asset deposited initially. /// @param _initialProduct The epoch state snapshot at initial depositing. /// @return _compoundedBalance The amount asset deposited after several liquidation. function _getCompoundedBalance( uint256 _initialBalance, uint112 _initialProduct, uint112 _currentProduct ) internal pure returns (uint256 _compoundedBalance) { // no balance before, return 0 if (_initialBalance == 0) { return 0; } // If stake was made before a pool-emptying event, then it has been fully cancelled with debt -- so, return 0 if (_initialProduct.epoch() < _currentProduct.epoch()) { return 0; } uint256 _exponentDiff = _currentProduct.exponent() - _initialProduct.exponent(); // Compute the compounded stake. If a scale change in P was made during the stake's lifetime, // account for it. If more than one scale change was made, then the stake has decreased by a factor of // at least 1e-9 -- so return 0. if (_exponentDiff == 0) { _compoundedBalance = (_initialBalance * uint256(_currentProduct.magnitude())) / uint256(_initialProduct.magnitude()); } else if (_exponentDiff == 1) { _compoundedBalance = (_initialBalance * uint256(_currentProduct.magnitude())) / uint256(_initialProduct.magnitude()) / DecrementalFloatingPoint.HALF_PRECISION; } else { _compoundedBalance = 0; } // If compounded deposit is less than a billionth of the initial deposit, return 0. // // NOTE: originally, this line was in place to stop rounding errors making the deposit too large. However, the error // corrections should ensure the error in P "favors the Pool", i.e. any given compounded deposit should slightly less // than it's theoretical value. // // Thus it's unclear whether this line is still really needed. if (_compoundedBalance < _initialBalance / 1e9) { _compoundedBalance = 0; } return _compoundedBalance; } /// @dev Internal function to get boost ratio for the given account. /// /// @param _account The address of the account to query. function _getBoostRatio(address _account) internal view returns (uint256 _boostRatio) { TokenBalance memory _balance = _balances[_account]; // no deposit before if (_balance.amount == 0) return 0; BoostCheckpoint memory _boostCheckpoint = boostCheckpoint[_account]; if (uint256(_balance.updateAt) == block.timestamp) { return _boostCheckpoint.boostRatio; } address _owner = getStakerVoteOwner[_account]; address _veHolder = _owner == address(0) ? _account : _owner; uint256 _nextIndex = _boostCheckpoint.historyIndex; uint256 _currentRatio = _boostCheckpoint.boostRatio; uint256 _prevTs = _balance.updateAt; // compute the time weighted boost from _balance.updateAt to now. uint256 _nowTs = _getWeekTs(_prevTs); unchecked { for (uint256 i = 0; i < 256; ++i) { // it is more than 4 years, should be enough if (_nowTs > block.timestamp) _nowTs = block.timestamp; _boostRatio += _currentRatio * (_nowTs - _prevTs); if (_nowTs == block.timestamp) break; uint256 _veBalance = IVotingEscrowHelper(veHelper).balanceOf(_veHolder, _nowTs); uint256 _veSupply = IVotingEscrowHelper(veHelper).totalSupply(_nowTs); (_currentRatio, _nextIndex) = _boostRatioAt(_owner, _balance, _veBalance, _veSupply, _nextIndex, _nowTs); _prevTs = _nowTs; _nowTs += WEEK; } _boostRatio /= uint256(block.timestamp - _balance.updateAt); } } /// @dev Internal function to get boost ratio at specific time point. /// /// Caller should make sure `t` is always a multiple of `WEEK`. function _boostRatioAt( address _owner, TokenBalance memory _balance, uint256 _veBalance, uint256 _veSupply, uint256 startIndex, uint256 t ) internal view returns (uint256, uint256) { // Binary search to find largest `index` that totalSupplyHistory[index].updateAt <= t. // The largest `index` may not be the correct one if there are multiple deposit/withdraw/liquidation // in the same block. However, we only care about the boost ratio after timestamp `t`, // it is tolerable to use the largest `index`. unchecked { uint256 endIndex = numTotalSupplyHistory - 1; while (startIndex < endIndex) { uint256 mid = (startIndex + endIndex + 1) >> 1; if (totalSupplyHistory[mid].updateAt <= t) startIndex = mid; else endIndex = mid - 1; } } // Find the actual balance base on the supply. TokenBalance memory _supply = totalSupplyHistory[startIndex]; uint256 _realBalance = _getCompoundedBalance(_balance.amount, _balance.product, _supply.product); uint256 _ownerBalance = _owner != address(0) ? _getVoteOwnerHistoryBalances(_owner, t) : _realBalance; return (_computeBoostRatio(_ownerBalance, _realBalance, _supply.amount, _veBalance, _veSupply), startIndex); } /// @dev Internal function to get `voteOwnerHistoryBalances` /// @param _owner The address of the owner. /// @param t The timestamp to query. function _getVoteOwnerHistoryBalances(address _owner, uint256 t) internal view returns (uint256) { uint256 _updateAt = voteOwnerBalances[_owner].updateAt; while (t > _updateAt) { uint256 w = voteOwnerHistoryBalances[_owner][t]; if (w != 0) return w; unchecked { t -= WEEK; } } return voteOwnerBalances[_owner].amount; } /// @dev Internal function to compute boost ratio with given parameters. function _computeBoostRatio( uint256 _ownerBalance, uint256 _balance, uint256 _supply, uint256 _veBalance, uint256 _veSupply ) internal pure returns (uint256) { unchecked { if (_balance == 0) return (PRECISION * 4) / 10; // Compute boost ratio with Curve's rule: min(balance, balance * 0.4 + 0.6 * veBalance * supply / veSupply) / balance uint256 _boostedBalance = (_ownerBalance * 4) / 10; if (_veSupply > 0) { _boostedBalance += (((_veBalance * _supply) / _veSupply) * 6) / 10; } _boostedBalance = (_boostedBalance * _balance) / _ownerBalance; if (_boostedBalance > _balance) { _boostedBalance = _balance; } return (_boostedBalance * PRECISION) / _balance; } } /// @dev Internal function to compute the smallest week aligned timestamp after given timestamp. /// @param timestamp The given timestamp. function _getWeekTs(uint256 timestamp) internal pure returns (uint256) { unchecked { return ((timestamp + WEEK - 1) / WEEK) * WEEK; } } }
// SPDX-License-Identifier: MIT pragma solidity =0.8.20; import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable-v4/token/ERC20/IERC20Upgradeable.sol"; import { SafeERC20Upgradeable } from "@openzeppelin/contracts-upgradeable-v4/token/ERC20/utils/SafeERC20Upgradeable.sol"; import { IFxBoostableRebalancePool } from "../../interfaces/f(x)/IFxBoostableRebalancePool.sol"; import { IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable-v4/token/ERC20/IERC20Upgradeable.sol"; import { IFxMarketV2 } from "../../interfaces/f(x)/IFxMarketV2.sol"; import { IFxTokenWrapper } from "../../interfaces/f(x)/IFxTokenWrapper.sol"; import { IFxTreasuryV2 } from "../../interfaces/f(x)/IFxTreasuryV2.sol"; import { ShareableRebalancePool } from "./ShareableRebalancePool.sol"; contract ShareableRebalancePoolV2 is ShareableRebalancePool { using SafeERC20Upgradeable for IERC20Upgradeable; /*************** * Constructor * ***************/ constructor( address _fxn, address _ve, address _veHelper, address _minter ) ShareableRebalancePool(_fxn, _ve, _veHelper, _minter) {} /**************************** * Public Mutated Functions * ****************************/ /// @inheritdoc IFxBoostableRebalancePool function liquidate(uint256 _maxAmount, uint256 _minBaseOut) external override onlyRole(LIQUIDATOR_ROLE) returns (uint256 _liquidated, uint256 _baseOut) { _checkpoint(address(0)); IFxTreasuryV2 _treasury = IFxTreasuryV2(treasury); if (_treasury.collateralRatio() >= liquidatableCollateralRatio) { revert CannotLiquidate(); } (, uint256 _maxLiquidatable) = _treasury.maxRedeemableFToken(liquidatableCollateralRatio); uint256 _amount = _maxLiquidatable; if (_amount > _maxAmount) { _amount = _maxAmount; } address _asset = asset; address _market = market; address _wrapper = wrapper; _liquidated = IERC20Upgradeable(_asset).balanceOf(address(this)); if (_amount > _liquidated) { // cannot liquidate more than assets in this contract. _amount = _liquidated; } IERC20Upgradeable(_asset).safeApprove(_market, 0); IERC20Upgradeable(_asset).safeApprove(_market, _amount); (_baseOut, ) = IFxMarketV2(_market).redeemFToken(_amount, _wrapper, _minBaseOut); _liquidated = _liquidated - IERC20Upgradeable(_asset).balanceOf(address(this)); emit Liquidate(_liquidated, _baseOut); // wrap base token if needed address _token = baseToken; if (_wrapper != address(this)) { _baseOut = IFxTokenWrapper(_wrapper).wrap(_baseOut); _token = IFxTokenWrapper(_wrapper).dst(); } // distribute liquidated base token _accumulateReward(_token, _baseOut); // notify loss _notifyLoss(_liquidated); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IFxBoostableRebalancePool { /********** * Events * **********/ /// @notice Emitted when user deposit asset into this contract. /// @param owner The address of asset owner. /// @param reciever The address of receiver of the asset in this contract. /// @param amount The amount of asset deposited. event Deposit(address indexed owner, address indexed reciever, uint256 amount); /// @notice Emitted when the amount of deposited asset changed due to liquidation or deposit or unlock. /// @param owner The address of asset owner. /// @param newDeposit The new amount of deposited asset. /// @param loss The amount of asset used by liquidation. event UserDepositChange(address indexed owner, uint256 newDeposit, uint256 loss); /// @notice Emitted when user withdraw asset. /// @param owner The address of asset owner. /// @param reciever The address of receiver of the asset. /// @param amount The amount of token to withdraw. event Withdraw(address indexed owner, address indexed reciever, uint256 amount); /// @notice Emitted when liquidation happens. /// @param liquidated The amount of asset liquidated. /// @param baseGained The amount of base token gained. event Liquidate(uint256 liquidated, uint256 baseGained); /// @notice Emitted when the address of reward wrapper is updated. /// @param oldWrapper The address of previous reward wrapper. /// @param newWrapper The address of current reward wrapper. event UpdateWrapper(address indexed oldWrapper, address indexed newWrapper); /// @notice Emitted when the liquidatable collateral ratio is updated. /// @param oldRatio The previous liquidatable collateral ratio. /// @param newRatio The current liquidatable collateral ratio. event UpdateLiquidatableCollateralRatio(uint256 oldRatio, uint256 newRatio); /********** * Errors * **********/ /// @dev Thrown then the src token mismatched. error ErrorWrapperSrcMismatch(); /// @dev Thrown then the dst token mismatched. error ErrorWrapperDstMismatch(); /// @dev Thrown when the deposited amount is zero. error DepositZeroAmount(); /// @dev Thrown when the withdrawn amount is zero. error WithdrawZeroAmount(); /// @dev Thrown the cannot liquidate. error CannotLiquidate(); /************************* * Public View Functions * *************************/ /// @notice Return the address of treasury contract. function treasury() external view returns (address); /// @notice Return the address of market contract. function market() external view returns (address); /// @notice Return the address of base token. function baseToken() external view returns (address); /// @notice Return the address of underlying token of this contract. function asset() external view returns (address); /// @notice Return the total amount of asset deposited to this contract. function totalSupply() external view returns (uint256); /// @notice Return the amount of deposited asset for some specific user. /// @param account The address of user to query. function balanceOf(address account) external view returns (uint256); /// @notice Return the current boost ratio for some specific user. /// @param account The address of user to query, multiplied by 1e18. function getBoostRatio(address account) external view returns (uint256); /**************************** * Public Mutated Functions * ****************************/ /// @notice Deposit some asset to this contract. /// @dev Use `amount=uint256(-1)` if you want to deposit all asset held. /// @param amount The amount of asset to deposit. /// @param receiver The address of recipient for the deposited asset. function deposit(uint256 amount, address receiver) external; /// @notice Withdraw asset from this contract. function withdraw(uint256 amount, address receiver) external; /// @notice Liquidate asset for base token. /// @param maxAmount The maximum amount of asset to liquidate. /// @param minBaseOut The minimum amount of base token should receive. /// @return liquidated The amount of asset liquidated. /// @return baseOut The amount of base token received. function liquidate(uint256 maxAmount, uint256 minBaseOut) external returns (uint256 liquidated, uint256 baseOut); }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0 || ^0.8.0; interface IFxMarket { /********** * Events * **********/ /// @notice Emitted when fToken or xToken is minted. /// @param owner The address of base token owner. /// @param recipient The address of receiver for fToken or xToken. /// @param baseTokenIn The amount of base token deposited. /// @param fTokenOut The amount of fToken minted. /// @param xTokenOut The amount of xToken minted. /// @param mintFee The amount of mint fee charged. event Mint( address indexed owner, address indexed recipient, uint256 baseTokenIn, uint256 fTokenOut, uint256 xTokenOut, uint256 mintFee ); /// @notice Emitted when someone redeem base token with fToken or xToken. /// @param owner The address of fToken and xToken owner. /// @param recipient The address of receiver for base token. /// @param fTokenBurned The amount of fToken burned. /// @param xTokenBurned The amount of xToken burned. /// @param baseTokenOut The amount of base token redeemed. /// @param redeemFee The amount of redeem fee charged. event Redeem( address indexed owner, address indexed recipient, uint256 fTokenBurned, uint256 xTokenBurned, uint256 baseTokenOut, uint256 redeemFee ); /// @notice Emitted when someone add more base token. /// @param owner The address of base token owner. /// @param recipient The address of receiver for fToken or xToken. /// @param baseTokenIn The amount of base token deposited. /// @param xTokenMinted The amount of xToken minted. event AddCollateral(address indexed owner, address indexed recipient, uint256 baseTokenIn, uint256 xTokenMinted); /// @notice Emitted when someone liquidate with fToken. /// @param owner The address of fToken and xToken owner. /// @param recipient The address of receiver for base token. /// @param fTokenBurned The amount of fToken burned. /// @param baseTokenOut The amount of base token redeemed. event UserLiquidate(address indexed owner, address indexed recipient, uint256 fTokenBurned, uint256 baseTokenOut); /// @notice Emitted when self liquidate with fToken. /// @param caller The address of caller. /// @param baseSwapAmt The amount of base token used to swap. /// @param baseTokenOut The amount of base token redeemed. /// @param fTokenBurned The amount of fToken liquidated. event SelfLiquidate(address indexed caller, uint256 baseSwapAmt, uint256 baseTokenOut, uint256 fTokenBurned); /**************************** * Public Mutated Functions * ****************************/ /// @notice Mint both fToken and xToken with some base token. /// @param baseIn The amount of base token supplied. /// @param recipient The address of receiver for fToken and xToken. /// @param minFTokenMinted The minimum amount of fToken should be received. /// @param minXTokenMinted The minimum amount of xToken should be received. /// @return fTokenMinted The amount of fToken should be received. /// @return xTokenMinted The amount of xToken should be received. function mint( uint256 baseIn, address recipient, uint256 minFTokenMinted, uint256 minXTokenMinted ) external returns (uint256 fTokenMinted, uint256 xTokenMinted); /// @notice Mint some fToken with some base token. /// @param baseIn The amount of base token supplied, use `uint256(-1)` to supply all base token. /// @param recipient The address of receiver for fToken. /// @param minFTokenMinted The minimum amount of fToken should be received. /// @return fTokenMinted The amount of fToken should be received. function mintFToken( uint256 baseIn, address recipient, uint256 minFTokenMinted ) external returns (uint256 fTokenMinted); /// @notice Mint some xToken with some base token. /// @param baseIn The amount of base token supplied, use `uint256(-1)` to supply all base token. /// @param recipient The address of receiver for xToken. /// @param minXTokenMinted The minimum amount of xToken should be received. /// @return xTokenMinted The amount of xToken should be received. /// @return bonus The amount of base token as bonus. function mintXToken( uint256 baseIn, address recipient, uint256 minXTokenMinted ) external returns (uint256 xTokenMinted, uint256 bonus); /// @notice Mint some xToken by add some base token as collateral. /// @param baseIn The amount of base token supplied, use `uint256(-1)` to supply all base token. /// @param recipient The address of receiver for xToken. /// @param minXTokenMinted The minimum amount of xToken should be received. /// @return xTokenMinted The amount of xToken should be received. function addBaseToken( uint256 baseIn, address recipient, uint256 minXTokenMinted ) external returns (uint256 xTokenMinted); /// @notice Redeem base token with fToken and xToken. /// @param fTokenIn the amount of fToken to redeem, use `uint256(-1)` to redeem all fToken. /// @param xTokenIn the amount of xToken to redeem, use `uint256(-1)` to redeem all xToken. /// @param recipient The address of receiver for base token. /// @param minBaseOut The minimum amount of base token should be received. /// @return baseOut The amount of base token should be received. /// @return bonus The amount of base token as bonus. function redeem( uint256 fTokenIn, uint256 xTokenIn, address recipient, uint256 minBaseOut ) external returns (uint256 baseOut, uint256 bonus); /// @notice Permissionless liquidate some fToken to increase the collateral ratio. /// @param fTokenIn the amount of fToken to supply, use `uint256(-1)` to liquidate all fToken. /// @param recipient The address of receiver for base token. /// @param minBaseOut The minimum amount of base token should be received. /// @return baseOut The amount of base token should be received. function liquidate( uint256 fTokenIn, address recipient, uint256 minBaseOut ) external returns (uint256 baseOut); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IFxMarketV2 { /********** * Events * **********/ /// @notice Emitted when fToken is minted. /// @param owner The address of base token owner. /// @param recipient The address of receiver for fToken or xToken. /// @param baseTokenIn The amount of base token deposited. /// @param fTokenOut The amount of fToken minted. /// @param mintFee The amount of mint fee charged. event MintFToken( address indexed owner, address indexed recipient, uint256 baseTokenIn, uint256 fTokenOut, uint256 mintFee ); /// @notice Emitted when xToken is minted. /// @param owner The address of base token owner. /// @param recipient The address of receiver for fToken or xToken. /// @param baseTokenIn The amount of base token deposited. /// @param xTokenOut The amount of xToken minted. /// @param bonus The amount of base token as bonus. /// @param mintFee The amount of mint fee charged. event MintXToken( address indexed owner, address indexed recipient, uint256 baseTokenIn, uint256 xTokenOut, uint256 bonus, uint256 mintFee ); /// @notice Emitted when someone redeem base token with fToken or xToken. /// @param owner The address of fToken and xToken owner. /// @param recipient The address of receiver for base token. /// @param fTokenBurned The amount of fToken burned. /// @param baseTokenOut The amount of base token redeemed. /// @param bonus The amount of base token as bonus. /// @param redeemFee The amount of redeem fee charged. event RedeemFToken( address indexed owner, address indexed recipient, uint256 fTokenBurned, uint256 baseTokenOut, uint256 bonus, uint256 redeemFee ); /// @notice Emitted when someone redeem base token with fToken or xToken. /// @param owner The address of fToken and xToken owner. /// @param recipient The address of receiver for base token. /// @param xTokenBurned The amount of xToken burned. /// @param baseTokenOut The amount of base token redeemed. /// @param redeemFee The amount of redeem fee charged. event RedeemXToken( address indexed owner, address indexed recipient, uint256 xTokenBurned, uint256 baseTokenOut, uint256 redeemFee ); /// @notice Emitted when the fee ratio for minting fToken is updated. /// @param defaultFeeRatio The new default fee ratio, multipled by 1e18. /// @param extraFeeRatio The new extra fee ratio, multipled by 1e18. event UpdateMintFeeRatioFToken(uint256 defaultFeeRatio, int256 extraFeeRatio); /// @notice Emitted when the fee ratio for minting xToken is updated. /// @param defaultFeeRatio The new default fee ratio, multipled by 1e18. /// @param extraFeeRatio The new extra fee ratio, multipled by 1e18. event UpdateMintFeeRatioXToken(uint256 defaultFeeRatio, int256 extraFeeRatio); /// @notice Emitted when the fee ratio for redeeming fToken is updated. /// @param defaultFeeRatio The new default fee ratio, multipled by 1e18. /// @param extraFeeRatio The new extra fee ratio, multipled by 1e18. event UpdateRedeemFeeRatioFToken(uint256 defaultFeeRatio, int256 extraFeeRatio); /// @notice Emitted when the fee ratio for redeeming xToken is updated. /// @param defaultFeeRatio The new default fee ratio, multipled by 1e18. /// @param extraFeeRatio The new extra fee ratio, multipled by 1e18. event UpdateRedeemFeeRatioXToken(uint256 defaultFeeRatio, int256 extraFeeRatio); /// @notice Emitted when the stability ratio is updated. /// @param oldRatio The previous collateral ratio to enter stability mode, multiplied by 1e18. /// @param newRatio The current collateral ratio to enter stability mode, multiplied by 1e18. event UpdateStabilityRatio(uint256 oldRatio, uint256 newRatio); /// @notice Emitted when the platform contract is updated. /// @param oldPlatform The address of previous platform contract. /// @param newPlatform The address of current platform contract. event UpdatePlatform(address indexed oldPlatform, address indexed newPlatform); /// @notice Emitted when the reserve pool contract is updated. /// @param oldReservePool The address of previous reserve pool contract. /// @param newReservePool The address of current reserve pool contract. event UpdateReservePool(address indexed oldReservePool, address indexed newReservePool); /// @notice Emitted when the RebalancePoolRegistry contract is updated. /// @param oldRegistry The address of previous RebalancePoolRegistry contract. /// @param newRegistry The address of current RebalancePoolRegistry contract. event UpdateRebalancePoolRegistry(address indexed oldRegistry, address indexed newRegistry); /// @notice Pause or unpause mint. /// @param oldStatus The previous status for mint. /// @param newStatus The current status for mint. event UpdateMintStatus(bool oldStatus, bool newStatus); /// @notice Pause or unpause redeem. /// @param oldStatus The previous status for redeem. /// @param newStatus The current status for redeem. event UpdateRedeemStatus(bool oldStatus, bool newStatus); /// @notice Pause or unpause fToken mint in stability mode. /// @param oldStatus The previous status for mint. /// @param newStatus The current status for mint. event UpdateFTokenMintStatusInStabilityMode(bool oldStatus, bool newStatus); /// @notice Pause or unpause xToken redeem in stability mode. /// @param oldStatus The previous status for redeem. /// @param newStatus The current status for redeem. event UpdateXTokenRedeemStatusInStabilityMode(bool oldStatus, bool newStatus); /********** * Errors * **********/ /// @dev Thrown when the caller if not fUSD contract. error ErrorCallerNotFUSD(); /// @dev Thrown when token mint is paused. error ErrorMintPaused(); /// @dev Thrown when fToken mint is paused in stability mode. error ErrorFTokenMintPausedInStabilityMode(); /// @dev Thrown when mint with zero amount base token. error ErrorMintZeroAmount(); /// @dev Thrown when the amount of fToken is not enough. error ErrorInsufficientFTokenOutput(); /// @dev Thrown when the amount of xToken is not enough. error ErrorInsufficientXTokenOutput(); /// @dev Thrown when token redeem is paused. error ErrorRedeemPaused(); /// @dev Thrown when xToken redeem is paused in stability mode. error ErrorXTokenRedeemPausedInStabilityMode(); /// @dev Thrown when redeem with zero amount fToken or xToken. error ErrorRedeemZeroAmount(); /// @dev Thrown when the amount of base token is not enough. error ErrorInsufficientBaseOutput(); /// @dev Thrown when the stability ratio is too large. error ErrorStabilityRatioTooLarge(); /// @dev Thrown when the default fee is too large. error ErrorDefaultFeeTooLarge(); /// @dev Thrown when the delta fee is too small. error ErrorDeltaFeeTooSmall(); /// @dev Thrown when the sum of default fee and delta fee is too large. error ErrorTotalFeeTooLarge(); /// @dev Thrown when the given address is zero. error ErrorZeroAddress(); /************************* * Public View Functions * *************************/ /// @notice The address of Treasury contract. function treasury() external view returns (address); /// @notice Return the address of base token. function baseToken() external view returns (address); /// @notice Return the address fractional base token. function fToken() external view returns (address); /// @notice Return the address leveraged base token. function xToken() external view returns (address); /// @notice Return the collateral ratio to enter stability mode, multiplied by 1e18. function stabilityRatio() external view returns (uint256); /**************************** * Public Mutated Functions * ****************************/ /// @notice Mint some fToken with some base token. /// @param baseIn The amount of wrapped value of base token supplied, use `uint256(-1)` to supply all base token. /// @param recipient The address of receiver for fToken. /// @param minFTokenMinted The minimum amount of fToken should be received. /// @return fTokenMinted The amount of fToken should be received. function mintFToken( uint256 baseIn, address recipient, uint256 minFTokenMinted ) external returns (uint256 fTokenMinted); /// @notice Mint some xToken with some base token. /// @param baseIn The amount of wrapped value of base token supplied, use `uint256(-1)` to supply all base token. /// @param recipient The address of receiver for xToken. /// @param minXTokenMinted The minimum amount of xToken should be received. /// @return xTokenMinted The amount of xToken should be received. /// @return bonus The amount of wrapped value of base token as bonus. function mintXToken( uint256 baseIn, address recipient, uint256 minXTokenMinted ) external returns (uint256 xTokenMinted, uint256 bonus); /// @notice Redeem base token with fToken. /// @param fTokenIn the amount of fToken to redeem, use `uint256(-1)` to redeem all fToken. /// @param recipient The address of receiver for base token. /// @param minBaseOut The minimum amount of wrapped value of base token should be received. /// @return baseOut The amount of wrapped value of base token should be received. /// @return bonus The amount of wrapped value of base token as bonus. function redeemFToken( uint256 fTokenIn, address recipient, uint256 minBaseOut ) external returns (uint256 baseOut, uint256 bonus); /// @notice Redeem base token with xToken. /// @param xTokenIn the amount of xToken to redeem, use `uint256(-1)` to redeem all xToken. /// @param recipient The address of receiver for base token. /// @param minBaseOut The minimum amount of wrapped value of base token should be received. /// @return baseOut The amount of wrapped value of base token should be received. function redeemXToken( uint256 xTokenIn, address recipient, uint256 minBaseOut ) external returns (uint256 baseOut); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IFxBoostableRebalancePool } from "./IFxBoostableRebalancePool.sol"; interface IFxShareableRebalancePool is IFxBoostableRebalancePool { /********** * Events * **********/ /// @notice Emitted when one user share votes to another user. /// @param owner The address of votes owner. /// @param staker The address of staker to share votes. event ShareVote(address indexed owner, address indexed staker); /// @notice Emitted when the owner cancel sharing to some staker. /// @param owner The address of votes owner. /// @param staker The address of staker to cancel votes share. event CancelShareVote(address indexed owner, address indexed staker); /// @notice Emitted when staker accept the vote sharing. /// @param staker The address of the staker. /// @param oldOwner The address of the previous vote sharing owner. /// @param newOwner The address of the current vote sharing owner. event AcceptSharedVote(address indexed staker, address indexed oldOwner, address indexed newOwner); /********** * Errors * **********/ /// @dev Thrown when caller shares votes to self. error ErrorSelfSharingIsNotAllowed(); /// @dev Thrown when a staker with shared votes try to share its votes to others. error ErrorCascadedSharingIsNotAllowed(); /// @dev Thrown when staker try to accept non-allowed vote sharing. error ErrorVoteShareNotAllowed(); /// @dev Thrown when staker try to reject a non-existed vote sharing. error ErrorNoAcceptedSharedVote(); /// @dev Thrown when the staker has ability to share ve balance. error ErrorVoteOwnerCannotStake(); /// @dev Thrown when staker try to accept twice. error ErrorRepeatAcceptSharedVote(); /************************* * Public View Functions * *************************/ /// @notice Return the owner of votes of some staker. /// @param account The address of user to query. function getStakerVoteOwner(address account) external view returns (address); /**************************** * Public Mutated Functions * ****************************/ /// @notice Withdraw asset from this contract on behalf of someone function withdrawFrom( address owner, uint256 amount, address receiver ) external; /// @notice Owner changes the vote sharing state for some user. /// @param staker The address of user to change. function toggleVoteSharing(address staker) external; /// @notice Staker accepts the vote sharing. /// @param newOwner The address of the owner of the votes. function acceptSharedVote(address newOwner) external; /// @notice Staker reject the current vote sharing. function rejectSharedVote() external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0 || ^0.8.0; interface IFxTokenWrapper { /// @notice Return the address of source token. function src() external view returns (address); /// @notice Return the address of destination token. function dst() external view returns (address); /// @notice Wrap some `src` token to `dst` token. /// /// @dev Assume that the token is already transfered to this contract. /// /// @param amount The amount of `src` token to wrap. /// @return uint256 The amount of `dst` token received. function wrap(uint256 amount) external returns (uint256); /// @notice Unwrap some `dst` token to `src` token. /// /// @dev Assume that the token is already transfered to this contract. /// /// @param amount The amount of `dst` token to unwrap. /// @return uint256 The amount of `src` token received. function unwrap(uint256 amount) external returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0 || ^0.8.0; interface IFxTreasury { /********** * Events * **********/ /// @notice Emitted when the net asset value is updated. /// @param price The new price of base token. /// @param fNav The new net asset value of fToken. event ProtocolSettle(uint256 price, uint256 fNav); /********* * Enums * *********/ enum MintOption { Both, FToken, XToken } /************************* * Public View Functions * *************************/ /// @notice Return the address of base token. function baseToken() external view returns (address); /// @notice Return the address fractional base token. function fToken() external view returns (address); /// @notice Return the address leveraged base token. function xToken() external view returns (address); /// @notice Return the address of strategy contract. function strategy() external view returns (address); /// @notice The last updated permissioned base token price. function lastPermissionedPrice() external view returns (uint256); /// @notice Return the total amount of base token deposited. function totalBaseToken() external view returns (uint256); /// @notice Return the total amount of base token managed by strategy. function strategyUnderlying() external view returns (uint256); /// @notice Return the current collateral ratio of fToken, multipled by 1e18. function collateralRatio() external view returns (uint256); /// @notice Convert unwrapped token amount to wrapped token amount. /// @param amount The unwrapped token amount. function convertToWrapped(uint256 amount) external view returns (uint256); /// @notice Convert wrapped token amount to unwrapped token amount. /// @param amount The wrapped token amount. function convertToUnwrapped(uint256 amount) external view returns (uint256); /// @notice Return current nav for base token, fToken and xToken. /// @return baseNav The nav for base token. /// @return fNav The nav for fToken. /// @return xNav The nav for xToken. function getCurrentNav() external view returns ( uint256 baseNav, uint256 fNav, uint256 xNav ); /// @notice Compute the amount of base token needed to reach the new collateral ratio. /// @param newCollateralRatio The target collateral ratio, multipled by 1e18. /// @return maxBaseIn The amount of base token needed. /// @return maxFTokenMintable The amount of fToken can be minted. function maxMintableFToken(uint256 newCollateralRatio) external view returns (uint256 maxBaseIn, uint256 maxFTokenMintable); /// @notice Compute the amount of base token needed to reach the new collateral ratio. /// @param newCollateralRatio The target collateral ratio, multipled by 1e18. /// @return maxBaseIn The amount of base token needed. /// @return maxXTokenMintable The amount of xToken can be minted. function maxMintableXToken(uint256 newCollateralRatio) external view returns (uint256 maxBaseIn, uint256 maxXTokenMintable); /// @notice Compute the amount of base token needed to reach the new collateral ratio, with incentive. /// @param newCollateralRatio The target collateral ratio, multipled by 1e18. /// @param incentiveRatio The extra incentive ratio, multipled by 1e18. /// @return maxBaseIn The amount of base token needed. /// @return maxXTokenMintable The amount of xToken can be minted. function maxMintableXTokenWithIncentive(uint256 newCollateralRatio, uint256 incentiveRatio) external view returns (uint256 maxBaseIn, uint256 maxXTokenMintable); /// @notice Compute the amount of fToken needed to reach the new collateral ratio. /// @param newCollateralRatio The target collateral ratio, multipled by 1e18. /// @return maxBaseOut The amount of base token redeemed. /// @return maxFTokenRedeemable The amount of fToken needed. function maxRedeemableFToken(uint256 newCollateralRatio) external view returns (uint256 maxBaseOut, uint256 maxFTokenRedeemable); /// @notice Compute the amount of xToken needed to reach the new collateral ratio. /// @param newCollateralRatio The target collateral ratio, multipled by 1e18. /// @return maxBaseOut The amount of base token redeemed. /// @return maxXTokenRedeemable The amount of xToken needed. function maxRedeemableXToken(uint256 newCollateralRatio) external view returns (uint256 maxBaseOut, uint256 maxXTokenRedeemable); /// @notice Compute the maximum amount of fToken can be liquidated. /// @param newCollateralRatio The target collateral ratio, multipled by 1e18. /// @param incentiveRatio The extra incentive ratio, multipled by 1e18. /// @return maxBaseOut The maximum amount of base token can liquidate, without incentive. /// @return maxFTokenLiquidatable The maximum amount of fToken can be liquidated. function maxLiquidatable(uint256 newCollateralRatio, uint256 incentiveRatio) external view returns (uint256 maxBaseOut, uint256 maxFTokenLiquidatable); /// @notice Return the exponential moving average of the leverage ratio. function leverageRatio() external view returns (uint256); /**************************** * Public Mutated Functions * ****************************/ /// @notice Mint fToken and xToken with some base token. /// @param baseIn The amount of base token deposited. /// @param recipient The address of receiver. /// @param option The mint option, xToken or fToken or both. /// @return fTokenOut The amount of fToken minted. /// @return xTokenOut The amount of xToken minted. function mint( uint256 baseIn, address recipient, MintOption option ) external returns (uint256 fTokenOut, uint256 xTokenOut); /// @notice Redeem fToken and xToken to base tokne. /// @param fTokenIn The amount of fToken to redeem. /// @param xTokenIn The amount of xToken to redeem. /// @param owner The owner of the fToken or xToken. /// @param baseOut The amount of base token redeemed. function redeem( uint256 fTokenIn, uint256 xTokenIn, address owner ) external returns (uint256 baseOut); /// @notice Add some base token to mint xToken with incentive. /// @param baseIn The amount of base token deposited. /// @param incentiveRatio The incentive ratio. /// @param recipient The address of receiver. /// @return xTokenOut The amount of xToken minted. function addBaseToken( uint256 baseIn, uint256 incentiveRatio, address recipient ) external returns (uint256 xTokenOut); /// @notice Liquidate fToken to base token with incentive. /// @param fTokenIn The amount of fToken to liquidate. /// @param incentiveRatio The incentive ratio. /// @param owner The owner of the fToken. /// @param baseOut The amount of base token liquidated. function liquidate( uint256 fTokenIn, uint256 incentiveRatio, address owner ) external returns (uint256 baseOut); /// @notice Settle the nav of base token, fToken and xToken. function protocolSettle() external; /// @notice Transfer some base token to strategy contract. /// @param amount The amount of token to transfer. function transferToStrategy(uint256 amount) external; /// @notice Notify base token profit from strategy contract. /// @param amount The amount of base token. function notifyStrategyProfit(uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IFxTreasuryV2 { /********** * Events * **********/ /// @notice Emitted when the platform contract is updated. /// @param oldPlatform The address of previous platform contract. /// @param newPlatform The address of current platform contract. event UpdatePlatform(address indexed oldPlatform, address indexed newPlatform); /// @notice Emitted when the RebalancePoolSplitter contract is updated. /// @param oldRebalancePoolSplitter The address of previous RebalancePoolSplitter contract. /// @param newRebalancePoolSplitter The address of current RebalancePoolSplitter. event UpdateRebalancePoolSplitter(address indexed oldRebalancePoolSplitter, address indexed newRebalancePoolSplitter); /// @notice Emitted when the price oracle contract is updated. /// @param oldPriceOracle The address of previous price oracle. /// @param newPriceOracle The address of current price oracle. event UpdatePriceOracle(address indexed oldPriceOracle, address indexed newPriceOracle); /// @notice Emitted when the strategy contract is updated. /// @param oldStrategy The address of previous strategy. /// @param newStrategy The address of current strategy. event UpdateStrategy(address indexed oldStrategy, address indexed newStrategy); /// @notice Emitted when the base token cap is updated. /// @param oldBaseTokenCap The value of previous base token cap. /// @param newBaseTokenCap The value of current base token cap. event UpdateBaseTokenCap(uint256 oldBaseTokenCap, uint256 newBaseTokenCap); /// @notice Emitted when the EMA sample interval is updated. /// @param oldSampleInterval The value of previous EMA sample interval. /// @param newSampleInterval The value of current EMA sample interval. event UpdateEMASampleInterval(uint256 oldSampleInterval, uint256 newSampleInterval); /// @notice Emitted when the reference price is updated. /// @param oldPrice The value of previous reference price. /// @param newPrice The value of current reference price. event Settle(uint256 oldPrice, uint256 newPrice); /// @notice Emitted when the ratio for rebalance pool is updated. /// @param oldRatio The value of the previous ratio, multipled by 1e9. /// @param newRatio The value of the current ratio, multipled by 1e9. event UpdateRebalancePoolRatio(uint256 oldRatio, uint256 newRatio); /// @notice Emitted when the ratio for harvester is updated. /// @param oldRatio The value of the previous ratio, multipled by 1e9. /// @param newRatio The value of the current ratio, multipled by 1e9. event UpdateHarvesterRatio(uint256 oldRatio, uint256 newRatio); /// @notice Emitted when someone harvest pending stETH rewards. /// @param caller The address of caller. /// @param totalRewards The amount of total harvested rewards. /// @param rebalancePoolRewards The amount of harvested rewards distributed to stability pool. /// @param harvestBounty The amount of harvested rewards distributed to caller as harvest bounty. event Harvest(address indexed caller, uint256 totalRewards, uint256 rebalancePoolRewards, uint256 harvestBounty); /********** * Errors * **********/ /// @dev Thrown when the collateral ratio is smaller than 100%. error ErrorCollateralRatioTooSmall(); /// @dev Thrown when mint exceed total capacity. error ErrorExceedTotalCap(); /// @dev Thrown when the oracle price is invalid. error ErrorInvalidOraclePrice(); /// @dev Thrown when the twap price is invalid. error ErrorInvalidTwapPrice(); /// @dev Thrown when initialize protocol twice. error ErrorProtocolInitialized(); /// @dev Thrown when the initial amount of base token is not enough. error ErrorInsufficientInitialBaseToken(); /// @dev Thrown when current is under collateral. error ErrorUnderCollateral(); /// @dev Thrown when the sample internal for EMA is too small. error ErrorEMASampleIntervalTooSmall(); /// @dev Thrown when the expense ratio exceeds `MAX_REBALANCE_POOL_RATIO`. error ErrorRebalancePoolRatioTooLarge(); /// @dev Thrown when the harvester ratio exceeds `MAX_HARVESTER_RATIO`. error ErrorHarvesterRatioTooLarge(); /// @dev Thrown when the given address is zero. error ErrorZeroAddress(); /********* * Enums * *********/ enum Action { None, MintFToken, MintXToken, RedeemFToken, RedeemXToken } /************************* * Public View Functions * *************************/ /// @notice Return the address of base token. function baseToken() external view returns (address); /// @notice Return the address fractional base token. function fToken() external view returns (address); /// @notice Return the address leveraged base token. function xToken() external view returns (address); /// @notice The reference base token price. function referenceBaseTokenPrice() external view returns (uint256); /// @notice The current base token price. function currentBaseTokenPrice() external view returns (uint256); /// @notice Return whether the price is valid. function isBaseTokenPriceValid() external view returns (bool); /// @notice Return the total amount of underlying value of base token deposited. function totalBaseToken() external view returns (uint256); /// @notice Return the address of strategy contract. function strategy() external view returns (address); /// @notice Return the total amount of base token managed by strategy. function strategyUnderlying() external view returns (uint256); /// @notice Return the current collateral ratio of fToken, multipled by 1e18. function collateralRatio() external view returns (uint256); /// @notice Return whether the system is under collateral. function isUnderCollateral() external view returns (bool); /// @notice Compute the amount of base token needed to reach the new collateral ratio. /// @param newCollateralRatio The target collateral ratio, multipled by 1e18. /// @return maxBaseIn The amount of underlying value of base token needed. /// @return maxFTokenMintable The amount of fToken can be minted. function maxMintableFToken(uint256 newCollateralRatio) external view returns (uint256 maxBaseIn, uint256 maxFTokenMintable); /// @notice Compute the amount of base token needed to reach the new collateral ratio. /// @param newCollateralRatio The target collateral ratio, multipled by 1e18. /// @return maxBaseIn The amount of underlying value of base token needed. /// @return maxXTokenMintable The amount of xToken can be minted. function maxMintableXToken(uint256 newCollateralRatio) external view returns (uint256 maxBaseIn, uint256 maxXTokenMintable); /// @notice Compute the amount of fToken needed to reach the new collateral ratio. /// @param newCollateralRatio The target collateral ratio, multipled by 1e18. /// @return maxBaseOut The amount of underlying value of base token redeemed. /// @return maxFTokenRedeemable The amount of fToken needed. function maxRedeemableFToken(uint256 newCollateralRatio) external view returns (uint256 maxBaseOut, uint256 maxFTokenRedeemable); /// @notice Compute the amount of xToken needed to reach the new collateral ratio. /// @param newCollateralRatio The target collateral ratio, multipled by 1e18. /// @return maxBaseOut The amount of underlying value of base token redeemed. /// @return maxXTokenRedeemable The amount of xToken needed. function maxRedeemableXToken(uint256 newCollateralRatio) external view returns (uint256 maxBaseOut, uint256 maxXTokenRedeemable); /// @notice Return the exponential moving average of the leverage ratio. function leverageRatio() external view returns (uint256); /// @notice Convert underlying token amount to wrapped token amount. /// @param amount The underlying token amount. function getWrapppedValue(uint256 amount) external view returns (uint256); /// @notice Convert wrapped token amount to underlying token amount. /// @param amount The wrapped token amount. function getUnderlyingValue(uint256 amount) external view returns (uint256); /// @notice Return the fee ratio distributed to rebalance pool, multipled by 1e9. function getRebalancePoolRatio() external view returns (uint256); /// @notice Return the fee ratio distributed to harvester, multipled by 1e9. function getHarvesterRatio() external view returns (uint256); /**************************** * Public Mutated Functions * ****************************/ /// @notice Initialize the protocol. /// @param baseIn The amount of underlying value of the base token used to initialize. function initializeProtocol(uint256 baseIn) external returns (uint256 fTokenOut, uint256 xTokenOut); /// @notice Mint fToken with some base token. /// @param baseIn The amount of underlying value of base token deposited. /// @param recipient The address of receiver. /// @return fTokenOut The amount of fToken minted. function mintFToken(uint256 baseIn, address recipient) external returns (uint256 fTokenOut); /// @notice Mint xToken with some base token. /// @param baseIn The amount of underlying value of base token deposited. /// @param recipient The address of receiver. /// @return xTokenOut The amount of xToken minted. function mintXToken(uint256 baseIn, address recipient) external returns (uint256 xTokenOut); /// @notice Redeem fToken and xToken to base tokne. /// @param fTokenIn The amount of fToken to redeem. /// @param xTokenIn The amount of xToken to redeem. /// @param owner The owner of the fToken or xToken. /// @param baseOut The amount of underlying value of base token redeemed. function redeem( uint256 fTokenIn, uint256 xTokenIn, address owner ) external returns (uint256 baseOut); /// @notice Settle the nav of base token, fToken and xToken. function settle() external; /// @notice Transfer some base token to strategy contract. /// @param amount The amount of token to transfer. function transferToStrategy(uint256 amount) external; /// @notice Notify base token profit from strategy contract. /// @param amount The amount of base token. function notifyStrategyProfit(uint256 amount) external; /// @notice Harvest pending rewards to stability pool. function harvest() external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.0 || ^0.8.0; // solhint-disable func-name-mixedcase // solhint-disable var-name-mixedcase interface ICurveTokenMinter { function token() external view returns (address); function controller() external view returns (address); function minted(address _user, address _gauge) external view returns (uint256); function allowed_to_mint_for(address _minter, address _user) external view returns (bool); function mint(address gauge_addr) external; function mint_many(address[8] memory gauge_addrs) external; function mint_for(address gauge_addr, address _for) external; function toggle_approve_mint(address minting_user) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // solhint-disable func-name-mixedcase interface IVotingEscrow { /*********** * Structs * ***********/ struct Point { int128 bias; int128 slope; uint256 ts; uint256 blk; } /************************* * Public View Functions * *************************/ function token() external view returns (address); function epoch() external view returns (uint256); function point_history(uint256 epoch) external view returns (Point memory); function user_point_epoch(address account) external view returns (uint256); function user_point_history(address account, uint256 epoch) external view returns (Point memory); /// @notice Get the timestamp for checkpoint `epoch` for `addr` /// @param addr User wallet address /// @param epoch User epoch number /// @return Epoch time of the checkpoint function user_point_history__ts(address addr, uint256 epoch) external view returns (uint256); /// @notice Get timestamp when `addr`'s lock finishes /// @param addr User wallet /// @return Epoch time of the lock end function locked__end(address addr) external view returns (uint256); /// @notice Calculate total voting power /// @dev Adheres to the ERC20 `totalSupply` interface for Aragon compatibility /// @return Total voting power function totalSupply() external view returns (uint256); /// @notice Get the current voting power for `msg.sender` /// @dev Adheres to the ERC20 `balanceOf` interface for Aragon compatibility /// @param addr User wallet address /// @return User voting power function balanceOf(address addr) external view returns (uint256); /// @notice time -> signed slope change function slope_changes(uint256 week) external view returns (int128); /**************************** * Public Mutated Functions * ****************************/ /// @notice Deposit `value` tokens for `addr` and add to the lock /// @dev Anyone (even a smart contract) can deposit for someone else, but /// cannot extend their locktime and deposit for a brand new user /// @param addr User's wallet address /// @param value Amount to add to user's lock function deposit_for(address addr, uint256 value) external; /// @notice Deposit `value` tokens for `msg.sender` and lock until `unlock_time` /// @param value Amount to deposit /// @param unlock_time Epoch time when tokens unlock, rounded down to whole weeks function create_lock(uint256 value, uint256 unlock_time) external; /// @notice Deposit `value` additional tokens for `msg.sender` /// without modifying the unlock time /// @param value Amount of tokens to deposit and add to the lock function increase_amount(uint256 value) external; /// @notice Extend the unlock time for `msg.sender` to `unlock_time` /// @param unlock_time New epoch time for unlocking function increase_unlock_time(uint256 unlock_time) external; /// @notice Withdraw all tokens for `msg.sender` /// @dev Only possible if the lock has expired function withdraw() external; /// @notice Record global data to checkpoint function checkpoint() external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IVotingEscrowHelper { /********** * Errors * **********/ /// @dev Thrown when try to checkpoint a future timestamp. error ErrorCheckpointFutureTime(); /// @dev Thrown when try to checkpoint a timestamp before start. error ErrorCheckpointInvalidPastTime(); /************************* * Public View Functions * *************************/ /// @notice Return the ve total supply at some specific time point. /// @param timestamp The time point in second to query. function totalSupply(uint256 timestamp) external view returns (uint256); /// @notice Return the ve balance of some user at some specific time point. /// @param account The address of user to query. /// @param timestamp The time point in second to query. function balanceOf(address account, uint256 timestamp) external view returns (uint256); /**************************** * Public Mutated Functions * ****************************/ /// @notice Snapshot the state of some user. /// @param account The address of user to checkpoint. function checkpoint(address account) external; /// @notice Snapshot the state of some user. /// @param account The address of user to checkpoint. /// @param timestamp The timestamp to checkpoint, should not less than current timestamp. function checkpoint(address account, uint256 timestamp) external; }
{ "optimizer": { "enabled": true, "runs": 200 }, "evmVersion": "shanghai", "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":"_fxn","type":"address"},{"internalType":"address","name":"_ve","type":"address"},{"internalType":"address","name":"_veHelper","type":"address"},{"internalType":"address","name":"_minter","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CannotLiquidate","type":"error"},{"inputs":[],"name":"ClaimOthersRewardToAnother","type":"error"},{"inputs":[],"name":"DepositZeroAmount","type":"error"},{"inputs":[],"name":"DuplicatedRewardToken","type":"error"},{"inputs":[],"name":"ErrorCascadedSharingIsNotAllowed","type":"error"},{"inputs":[],"name":"ErrorNoAcceptedSharedVote","type":"error"},{"inputs":[],"name":"ErrorRepeatAcceptSharedVote","type":"error"},{"inputs":[],"name":"ErrorSelfSharingIsNotAllowed","type":"error"},{"inputs":[],"name":"ErrorVoteOwnerCannotStake","type":"error"},{"inputs":[],"name":"ErrorVoteShareNotAllowed","type":"error"},{"inputs":[],"name":"ErrorWrapperDstMismatch","type":"error"},{"inputs":[],"name":"ErrorWrapperSrcMismatch","type":"error"},{"inputs":[],"name":"NotActiveRewardToken","type":"error"},{"inputs":[],"name":"NotRewardDistributor","type":"error"},{"inputs":[],"name":"RewardDistributionNotFinished","type":"error"},{"inputs":[],"name":"RewardDistributorIsZero","type":"error"},{"inputs":[],"name":"WithdrawZeroAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"staker","type":"address"},{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"AcceptSharedVote","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"staker","type":"address"}],"name":"CancelShareVote","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"reciever","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DepositReward","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"liquidated","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"baseGained","type":"uint256"}],"name":"Liquidate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"distributor","type":"address"}],"name":"RegisterRewardToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"staker","type":"address"}],"name":"ShareVote","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"}],"name":"UnregisterRewardToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldRatio","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newRatio","type":"uint256"}],"name":"UpdateLiquidatableCollateralRatio","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"oldDistributor","type":"address"},{"indexed":true,"internalType":"address","name":"newDistributor","type":"address"}],"name":"UpdateRewardDistributor","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"oldReceiver","type":"address"},{"indexed":true,"internalType":"address","name":"newReceiver","type":"address"}],"name":"UpdateRewardReceiver","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldWrapper","type":"address"},{"indexed":true,"internalType":"address","name":"newWrapper","type":"address"}],"name":"UpdateWrapper","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"newDeposit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"loss","type":"uint256"}],"name":"UserDepositChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"reciever","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIQUIDATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARD_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VE_SHARING_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WITHDRAW_FROM_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"acceptSharedVote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"boostCheckpoint","outputs":[{"internalType":"uint64","name":"boostRatio","type":"uint64"},{"internalType":"uint64","name":"historyIndex","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"checkpoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_tokens","type":"address[]"}],"name":"claimHistorical","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address[]","name":"_tokens","type":"address[]"}],"name":"claimHistorical","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"claimable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"claimed","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"depositReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"distributors","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"epochToExponentToRewardSnapshot","outputs":[{"internalType":"uint64","name":"timestamp","type":"uint64"},{"internalType":"uint192","name":"integral","type":"uint192"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fxn","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gauge","outputs":[{"internalType":"address","name":"gauge","type":"address"},{"internalType":"uint64","name":"claimAt","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getActiveRewardTokens","outputs":[{"internalType":"address[]","name":"_rewardTokens","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"getBoostRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getHistoricalRewardTokens","outputs":[{"internalType":"address[]","name":"_rewardTokens","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"getStakerVoteOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_market","type":"address"},{"internalType":"address","name":"_gauge","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isStakerAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastAssetLossError","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liquidatableCollateralRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxAmount","type":"uint256"},{"internalType":"uint256","name":"_minBaseOut","type":"uint256"}],"name":"liquidate","outputs":[{"internalType":"uint256","name":"_liquidated","type":"uint256"},{"internalType":"uint256","name":"_baseOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"market","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numTotalSupplyHistory","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"pendingRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"periodLength","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_distributor","type":"address"}],"name":"registerRewardToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rejectSharedVote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardData","outputs":[{"internalType":"uint96","name":"queued","type":"uint96"},{"internalType":"uint80","name":"rate","type":"uint80"},{"internalType":"uint40","name":"lastUpdate","type":"uint40"},{"internalType":"uint40","name":"finishAt","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardReceiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newReceiver","type":"address"}],"name":"setRewardReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_staker","type":"address"}],"name":"toggleVoteSharing","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalSupplyHistory","outputs":[{"internalType":"uint112","name":"product","type":"uint112"},{"internalType":"uint104","name":"amount","type":"uint104"},{"internalType":"uint40","name":"updateAt","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"unregisterRewardToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newRatio","type":"uint256"}],"name":"updateLiquidatableCollateralRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_newDistributor","type":"address"}],"name":"updateRewardDistributor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newWrapper","type":"address"}],"name":"updateWrapper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"userRewardSnapshot","outputs":[{"components":[{"internalType":"uint128","name":"pending","type":"uint128"},{"internalType":"uint128","name":"claimed","type":"uint128"}],"internalType":"struct MultipleRewardCompoundingAccumulator.ClaimData","name":"rewards","type":"tuple"},{"components":[{"internalType":"uint64","name":"timestamp","type":"uint64"},{"internalType":"uint192","name":"integral","type":"uint192"}],"internalType":"struct MultipleRewardCompoundingAccumulator.RewardSnapshot","name":"checkpoint","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ve","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"veHelper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"voteOwnerBalances","outputs":[{"internalType":"uint112","name":"product","type":"uint112"},{"internalType":"uint104","name":"amount","type":"uint104"},{"internalType":"uint40","name":"updateAt","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"voteOwnerHistoryBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"withdrawFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wrapper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
61012060405234801562000011575f80fd5b506040516200614b3803806200614b83398101604081905262000034916200007b565b62093a806080526001600160a01b0393841660a05291831660c052821660e0521661010052620000d5565b80516001600160a01b038116811462000076575f80fd5b919050565b5f805f80608085870312156200008f575f80fd5b6200009a856200005f565b9350620000aa602086016200005f565b9250620000ba604086016200005f565b9150620000ca606086016200005f565b905092959194509250565b60805160a05160c05160e05161010051615fc8620001835f395f818161040e015261299701525f81816108e001528181612b04015281816143a1015261442e01525f81816105220152818161323b01526132d501525f8181610648015281816121990152818161290001528181612a0f01528181612aaf015281816151f901526152fe01525f8181610abd015281816123b1015281816138570152818161399a0152613a460152615fc85ff3fe608060405234801561000f575f80fd5b50600436106103c9575f3560e01c8063818c371511610200578063d1b5893c1161011f578063dffaf449116100b4578063f38e412811610084578063f38e412814610c4c578063f593a62a14610c7a578063fbb4ad5b14610c8e578063fdc5aa5d14610c96578063ff9fe67214610ca9575f80fd5b8063dffaf44914610b54578063e162402f14610b67578063e75c9a4e14610b7a578063f305ce4714610b84575f80fd5b8063d547741f116100ef578063d547741f14610b08578063d5a3aa7c14610b1b578063dae254dd14610b2e578063db02794614610b41575f80fd5b8063d1b5893c14610a9b578063d296d1f114610aa5578063d2ca211514610ab8578063d4570c1c14610af5575f80fd5b8063a6f19c8411610195578063c0c53b8b11610165578063c0c53b8b14610a02578063c0c7a7b414610a15578063c55dae6314610a5f578063cc64278414610a73575f80fd5b8063a6f19c8414610986578063a972985e146109d3578063ac210cc7146109e6578063ad347817146109fa575f80fd5b80639a2a42b8116101d05780639a2a42b81461094f5780639b4bf63e146109625780639d0d5bbd1461096c578063a217fddf1461097f575f80fd5b8063818c3715146108db578063838163ff1461090257806391d1485414610915578063982b0aa814610928575f80fd5b806336568abe116102ec5780636641d9a0116102815780636e553f65116102515780636e553f651461088e57806370a08231146108a15780637db4e28f146108b457806380f55605146108c7575f80fd5b80636641d9a0146107c15780636720a1201461083f5780636be2e80d146108675780636d750d801461087a575f80fd5b80634c3da2da116102bc5780634c3da2da146107105780634e71d92d1461077c5780635c8254301461078457806361d027b3146107ad575f80fd5b806336568abe14610630578063383d5dc81461064357806338d52e0f1461066a57806348e5d9f81461067e575f80fd5b80631f8507161161036257806330ae4bba1161033257806330ae4bba1461058c57806331d7a262146105a157806332ff6afb146105c957806333eda141146105dc575f80fd5b80631f8507161461051d57806321c0b34214610544578063248a9ca3146105575780632f2ff15d14610579575f80fd5b806315dec2951161039d57806315dec2951461049f57806316d8887a146104ca57806318160ddd146104f15780631e83409a1461050a575f80fd5b8062f714ce146103cd57806301ffc9a7146103e157806307546172146104095780630c9cbf0e14610448575b5f80fd5b6103df6103db3660046158c3565b5050565b005b6103f46103ef3660046158f1565b610cbc565b60405190151581526020015b60405180910390f35b6104307f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610400565b610491610456366004615918565b6001600160a01b038281165f90815260ff6020908152604080832093851683529290522054600160801b90046001600160801b031692915050565b604051908152602001610400565b6104916104ad366004615944565b61013e60209081525f928352604080842090915290825290205481565b6104917f5e17fc5225d4a099df75359ce1f405503ca79498a8dc46a7d583235a0ee45c1681565b61013454600160701b90046001600160681b0316610491565b6103df61051836600461596e565b610cf2565b6104307f000000000000000000000000000000000000000000000000000000000000000081565b6103df610552366004615918565b610cff565b610491610565366004615989565b5f9081526097602052604090206001015490565b6103df6105873660046158c3565b610d62565b610594610d8b565b60405161040091906159a0565b6105b46105af36600461596e565b610e34565b60408051928352602083019190915201610400565b6103df6105d736600461596e565b610eb3565b6106106105ea36600461596e565b61013c6020525f90815260409020546001600160401b0380821691600160401b90041682565b604080516001600160401b03938416815292909116602083015201610400565b6103df61063e3660046158c3565b611080565b6104307f000000000000000000000000000000000000000000000000000000000000000081565b61013354610430906001600160a01b031681565b6106d161068c36600461596e565b60ca6020525f90815260409020546001600160601b038116906001600160501b03600160601b8204169064ffffffffff600160b01b8204811691600160d81b90041684565b604080516001600160601b0390951685526001600160501b03909316602085015264ffffffffff91821692840192909252166060820152608001610400565b61075561071e366004615944565b60fe60209081525f92835260408084209091529082529020546001600160401b03811690600160401b90046001600160c01b031682565b604080516001600160401b0390931683526001600160c01b03909116602083015201610400565b6103df6110ff565b61043061079236600461596e565b6101406020525f90815260409020546001600160a01b031681565b61012f54610430906001600160a01b031681565b61080b6107cf366004615989565b6101386020525f90815260409020546001600160701b03811690600160701b81046001600160681b031690600160d81b900464ffffffffff1683565b604080516001600160701b0390941684526001600160681b03909216602084015264ffffffffff1690820152606001610400565b61043061084d36600461596e565b60fd6020525f90815260409020546001600160a01b031681565b6103df610875366004615a93565b61110a565b6104915f80516020615f7383398151915281565b6103df61089c3660046158c3565b61118c565b6104916108af36600461596e565b61153f565b6103df6108c2366004615944565b6115b7565b61013054610430906001600160a01b031681565b6104307f000000000000000000000000000000000000000000000000000000000000000081565b6103df610910366004615ac4565b611691565b6103f46109233660046158c3565b611703565b6104917f24ba51fc201891c1803eeafedeae076c0a88d453c20b1073528aa34d0cf55b7981565b6103df61095d36600461596e565b61172d565b6104916101395481565b6103df61097a366004615989565b61192a565b6104915f81565b610131546109ac906001600160a01b03811690600160a01b90046001600160401b031682565b604080516001600160a01b0390931683526001600160401b03909116602083015201610400565b6103df6109e136600461596e565b61197b565b61013a54610430906001600160a01b031681565b610594611995565b6103df610a10366004615b10565b611a39565b61080b610a2336600461596e565b61013d6020525f90815260409020546001600160701b03811690600160701b81046001600160681b031690600160d81b900464ffffffffff1683565b61013254610430906001600160a01b031681565b610430610a8136600461596e565b60c96020525f90815260409020546001600160a01b031681565b6104916101375481565b6105b4610ab3366004615b58565b611d70565b610adf7f000000000000000000000000000000000000000000000000000000000000000081565b60405164ffffffffff9091168152602001610400565b610491610b03366004615918565b612196565b6103df610b163660046158c3565b61226a565b610491610b2936600461596e565b61228e565b6103df610b3c36600461596e565b612298565b6103df610b4f36600461596e565b6122f6565b6103df610b62366004615918565b612493565b6103df610b75366004615b78565b612584565b61049161013b5481565b610c02610b92366004615918565b60ff60209081525f92835260408084208252918352918190208151808301835281546001600160801b038082168352600160801b909104168185015282518084019093526001909101546001600160401b0381168352600160401b90046001600160c01b03169282019290925282565b60405161040092919082516001600160801b039081168252602093840151168382015281516001600160401b031660408201529101516001600160c01b0316606082015260800190565b6103f4610c5a366004615918565b61013f60209081525f928352604080842090915290825290205460ff1681565b6104915f80516020615f5383398151915281565b6103df6125b9565b6103df610ca436600461596e565b6125fa565b6103df610cb7366004615918565b612786565b5f6001600160e01b03198216637965db0b60e01b1480610cec57506301ffc9a760e01b6001600160e01b03198316145b92915050565b610cfc815f610cff565b50565b610d07612850565b6001600160a01b0382163314801590610d2857506001600160a01b03811615155b15610d4657604051630894de8d60e01b815260040160405180910390fd5b610d4f826128a9565b610d598282612c1a565b6103db60018055565b5f82815260976020526040902060010154610d7c81612cb8565b610d868383612cc2565b505050565b60605f610d9860cb612d2d565b9050806001600160401b03811115610db257610db26159ec565b604051908082528060200260200182016040528015610ddb578160200160208202803683370190505b5091505f5b81811015610e2f57610df360cb82612d36565b838281518110610e0557610e05615bac565b6001600160a01b039092166020928302919091019091015280610e2781615bd4565b915050610de0565b505090565b6001600160a01b0381165f90815260ca60209081526040808320815160808101835290546001600160601b03811682526001600160501b03600160601b8204169382019390935264ffffffffff600160b01b8404811692820192909252600160d81b9092041660608201528190610eaa90612d41565b91509150915091565b6001600160a01b0381165f90815261013f602090815260408083203380855292529091205460ff16610ef85760405163a0def43760e01b815260040160405180910390fd5b6001600160a01b038082165f908152610140602052604090205481169083168103610f365760405163097000d560e41b815260040160405180910390fd5b6001600160a01b03811615610f5457610f4f8183612dfc565b610f5d565b610f5d826128a9565b6001600160a01b038281165f9081526101406020908152604080832080546001600160a01b03191694881694909417909355610135815282822083516060808201865291546001600160701b038082168352600160701b8083046001600160681b0390811685880152600160d81b9384900464ffffffffff908116868b015289519687018a5261013454938416875291830416958501959095520490921693810193909352919061100e8683612fbb565b90508260200151816020018181516110269190615bec565b6001600160681b031690525061103f858785848661312e565b6040516001600160a01b03808816915f918816907f691c95c6dfadb8a9643f02b1ee3706982f7a9361ca534563e1f5944ae1471cac908390a4505050505050565b6001600160a01b03811633146110f55760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6103db82826133cc565b33610cfc815f610cff565b611112612850565b3361111c816128a9565b6001600160a01b038082165f90815260fd6020526040902054168061113e5750805b5f5b83518110156111805761116d8385838151811061115f5761115f615bac565b602002602001015184613432565b508061117881615bd4565b915050611140565b505050610cfc60018055565b6111a35f80516020615f5383398151915282611703565b156111c15760405163433869fd60e11b815260040160405180910390fd5b6101335433906001600160a01b031660018401611243576040516370a0823160e01b81526001600160a01b0383811660048301528216906370a0823190602401602060405180830381865afa15801561121c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112409190615c0c565b93505b835f03611263576040516322c1ccd560e21b815260040160405180910390fd5b6112786001600160a01b038216833087613558565b611281836128a9565b6040805160608082018352610134546001600160701b038082168452600160701b8083046001600160681b039081166020808801918252600160d81b9586900464ffffffffff908116898b01526001600160a01b038d165f90815261013583528a81208b51808b018d52905497881681529587049094168583015295909404909416828801528651948501875280855291840182905294830152805192939288919061132e908390615bec565b6001600160681b031690525064ffffffffff4216604084015260208201805188919061135b908390615bec565b6001600160681b03169052506001600160a01b038087165f9081526101406020526040902054168015611403576001600160a01b0381165f90815261013d6020908152604091829020825160608101845290546001600160701b0381168252600160701b81046001600160681b0316928201838152600160d81b90910464ffffffffff169382019390935293508991906113f6908390615bec565b6001600160681b03169052505b61140c846135c3565b6001600160a01b0387165f908152610135602090815260409182902085518154928701519387015164ffffffffff16600160d81b026001600160d81b036001600160681b03909516600160701b026001600160d81b03199094166001600160701b0390921691909117929092179290921617905561148d878285858861312e565b866001600160a01b0316866001600160a01b03167f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f628a6040516114d291815260200190565b60405180910390a3866001600160a01b03167f5fa7d0e13a31540b6d42936e522173de31fa0c53aa5aff71e63c60fe02b2b50e84602001515f60405161152d9291906001600160681b03929092168252602082015260400190565b60405180910390a25050505050505050565b6001600160a01b0381165f90815261013560209081526040808320815160608101835290546001600160701b03808216808452600160701b83046001600160681b0316958401869052600160d81b90920464ffffffffff16938301939093526101345491936115b09390921661373d565b9392505050565b336115c360cb8461382e565b6115e05760405163ad2882d360e01b815260040160405180910390fd5b6001600160a01b038381165f90815260c9602052604090205481169082161461161c5760405163af216a6b60e01b815260040160405180910390fd5b8115611637576116376001600160a01b038416823085613558565b61163f61384f565b6116498383613998565b826001600160a01b03167f4f7fd5c9e17300a4800fd572ea53fc291e2ee7470d73346d16b357faee4e72108360405161168491815260200190565b60405180910390a2505050565b611699612850565b6116a2826128a9565b6001600160a01b038083165f90815260fd602052604090205416806116c45750815b5f5b82518110156116f8576116e58484838151811061115f5761115f615bac565b50806116f081615bd4565b9150506116c6565b50506103db60018055565b5f9182526097602090815260408084206001600160a01b0393909316845291905290205460ff1690565b5f61173781612cb8565b6101325460408051632e7dc6af60e01b815290516001600160a01b0392831692851691632e7dc6af9160048083019260209291908290030181865afa158015611782573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117a69190615c23565b6001600160a01b0316146117cd57604051632124403760e11b815260040160405180910390fd5b61013a546001600160a01b03163081148015906118ba5750826001600160a01b031663d48532b36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611821573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118459190615c23565b6001600160a01b0316816001600160a01b031663d48532b36040518163ffffffff1660e01b8152600401602060405180830381865afa15801561188a573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118ae9190615c23565b6001600160a01b031614155b156118d8576040516302bae16b60e01b815260040160405180910390fd5b61013a80546001600160a01b0319166001600160a01b0385811691821790925560405190918316907fe6ed57be293efa66c0a505ccdf4018974586d424d796b8ae52745cf0a1f2e2d3905f90a3505050565b5f61193481612cb8565b61013980549083905560408051828152602081018590527fbf7572abbb7816b05b5dd2f50fc9e818813c1d4c6f51e99e7ae15b5604fa0396910160405180910390a1505050565b611983612850565b61198c816128a9565b610cfc60018055565b60605f6119a260cd612d2d565b9050806001600160401b038111156119bc576119bc6159ec565b6040519080825280602002602001820160405280156119e5578160200160208202803683370190505b5091505f5b81811015610e2f576119fd60cd82612d36565b838281518110611a0f57611a0f615bac565b6001600160a01b039092166020928302919091019091015280611a3181615bd4565b9150506119ea565b5f54610100900460ff1615808015611a5757505f54600160ff909116105b80611a705750303b158015611a7057505f5460ff166001145b611ad35760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016110ec565b5f805460ff191660011790558015611af4575f805461ff0019166101001790555b611afc613b02565b611b04613b32565b611b0e5f33613b60565b611b255f80516020615f7383398151915233613b60565b61012f80546001600160a01b038087166001600160a01b0319928316811790935561013080548783169084161790556101318054918616919092161790556040805163c55dae6360e01b8152905163c55dae63916004808201926020929091908290030181865afa158015611b9c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bc09190615c23565b6101325f6101000a8154816001600160a01b0302191690836001600160a01b03160217905550836001600160a01b031663a8694e576040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c22573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c469190615c23565b61013380546001600160a01b03929092166001600160a01b031992831617905561013a805490911630179055670de0b6b3a764000061013480546001600160701b039283166cffffffffffffffffffffffffff60701b90911617600160d81b4264ffffffffff908116820292909217928390555f80526101386020527f466a001727fe4c50af81de09fe9d15b89f88e442506e33af81822399cd821bb080546001600160d81b039585166001600160d81b031990911617600160701b8086046001600160681b031602179490941692819004909116021790556001610137558015611d6a575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b5f807f5e17fc5225d4a099df75359ce1f405503ca79498a8dc46a7d583235a0ee45c16611d9c81612cb8565b611da55f6128a9565b61012f54610139546040805163b4eae1cb60e01b815290516001600160a01b0390931692839163b4eae1cb9160048083019260209291908290030181865afa158015611df3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e179190615c0c565b10611e355760405163bf87c7d560e01b815260040160405180910390fd5b610139546040516271691b60e21b81525f916001600160a01b038416916301c5a46c91611e689160040190815260200190565b6040805180830381865afa158015611e82573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ea69190615c3e565b915081905087811115611eb65750865b610133546101305461013a546040516370a0823160e01b81523060048201526001600160a01b0393841693928316929091169083906370a0823190602401602060405180830381865afa158015611f0f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f339190615c0c565b985088841115611f41578893505b611f556001600160a01b038416835f613be5565b611f696001600160a01b0384168386613be5565b6040516368674c7d60e11b8152600481018590526001600160a01b038281166024830152604482018c905283169063d0ce98fa9060640160408051808303815f875af1158015611fbb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fdf9190615c3e565b506040516370a0823160e01b81523060048201529098506001600160a01b038416906370a0823190602401602060405180830381865afa158015612025573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120499190615c0c565b612053908a615c60565b60408051828152602081018b9052919a507f253e5385159062a101837d58c10ad4694c58979ebc3ba6b5cb2cbba2fe461692910160405180910390a1610132546001600160a01b03908116908216301461217457604051630ea598cb60e41b8152600481018a90526001600160a01b0383169063ea598cb0906024016020604051808303815f875af11580156120eb573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061210f9190615c0c565b9850816001600160a01b031663d48532b36040518163ffffffff1660e01b8152600401602060405180830381865afa15801561214d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121719190615c23565b90505b61217e818a613cf8565b6121878a613eba565b50505050505050509250929050565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031603612259576001600160a01b038084165f90815260ff602090815260408083209386168352929052908120546001600160801b0316908161220c8686614005565b6122169190615c60565b90505f6122228661228e565b90505f670de0b6b3a76400006122388385615c73565b6122429190615c9e565b905061224e8185615cbd565b945050505050610cec565b6122638383614005565b9050610cec565b5f8281526097602052604090206001015461228481612cb8565b610d8683836133cc565b5f610cec82614221565b335f81815260fd602052604080822080546001600160a01b031981166001600160a01b038781169182179093559251911692839185917f49ddedcc7960d57ef16bbd5dda435520c8a203a051b3eb1a02f7e71e77478bf091a4505050565b5f80516020615f7383398151915261230d81612cb8565b61231860cb8361382e565b6123355760405163ad2882d360e01b815260040160405180910390fd5b6001600160a01b0382165f90815260ca60209081526040808320815160808101835290546001600160601b03811682526001600160501b03600160601b8204169382019390935264ffffffffff600160b01b8404811692820192909252600160d81b90920416606082015290806123ab83612d41565b915091507f000000000000000000000000000000000000000000000000000000000000000064ffffffffff16835f01516001600160601b031610156123ee575f83525b82516001600160601b0316820181011561241b57604051630e6d89d360e21b815260040160405180910390fd5b50612429905060cb846144eb565b506001600160a01b0383165f90815260c96020526040902080546001600160a01b031916905561245a60cd846144ff565b506040516001600160a01b038416907fbfa4256e0ed8b426ac2df0a3469f79ee315552c50c46d123cfbc165252d8550e905f90a2505050565b5f80516020615f738339815191526124aa81612cb8565b6001600160a01b0382166124d157604051632fea089160e11b815260040160405180910390fd5b6124dc60cb8461382e565b156124fa57604051638599b12960e01b815260040160405180910390fd5b61250560cb846144ff565b506001600160a01b038381165f90815260c96020526040902080546001600160a01b03191691841691909117905561253e60cd846144eb565b50816001600160a01b0316836001600160a01b03167fd58451dda05155bb82ebdd6dfb79317f4ad9e8a480a422409a044b4c02286ed160405160405180910390a3505050565b7f24ba51fc201891c1803eeafedeae076c0a88d453c20b1073528aa34d0cf55b796125ae81612cb8565b611d6a848484614513565b335f81815261014060205260409020546001600160a01b0316806125f0576040516306bc241560e31b815260040160405180910390fd5b6103db8183612dfc565b5f80516020615f5383398151915261261181612cb8565b336001600160a01b03831681900361263c576040516346023c5b60e01b815260040160405180910390fd5b6001600160a01b038181165f9081526101406020526040902054161561267557604051630b0a071f60e31b815260040160405180910390fd5b6001600160a01b038082165f90815261013f602090815260408083209387168352929052205460ff16156126fe576001600160a01b038082165f81815261013f6020908152604080832094881680845294909152808220805460ff19169055517fc8381dbc9d72f294db9b9a633c7497147bca68466d717a41aa1c9d4c4221f6409190a3612758565b6001600160a01b038082165f81815261013f6020908152604080832094881680845294909152808220805460ff19166001179055517f8f5b9ecbfffe5c27362de218379661bd1cb0afa18563c33122045df8613099ec9190a35b6001600160a01b038381165f9081526101406020526040902054818316911603610d8657610d868184612dfc565b5f80516020615f7383398151915261279d81612cb8565b6001600160a01b0382166127c457604051632fea089160e11b815260040160405180910390fd5b6127cf60cb8461382e565b6127ec5760405163ad2882d360e01b815260040160405180910390fd5b6001600160a01b038084165f81815260c9602052604080822080548786166001600160a01b0319821681179092559151919094169392849290917f1fad2e3fecc3cdff6159846b2a5d093b3bc70746158fcf6830313e74d852f2219190a450505050565b6002600154036128a25760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016110ec565b6002600155565b610131546001600160a01b0316158015906128e45750610131546128e1906201518090600160a01b90046001600160401b0316615cbd565b42115b15612ad7576040516370a0823160e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561294d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129719190615c0c565b610131546040516335313c2160e11b81526001600160a01b0391821660048201529192507f00000000000000000000000000000000000000000000000000000000000000001690636a627842906024015f604051808303815f87803b1580156129d8575f80fd5b505af11580156129ea573d5f803e3d5ffd5b50506040516370a0823160e01b81523060048201525f92508391506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015612a54573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612a789190615c0c565b612a829190615c60565b610131805467ffffffffffffffff60a01b1916600160a01b426001600160401b0316021790559050612ad47f000000000000000000000000000000000000000000000000000000000000000082613998565b50505b6001600160a01b038082165f81815261014060205260409020549091169015612b90576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081169063a972985e90831615612b395782612b3b565b835b6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024015f604051808303815f87803b158015612b79575f80fd5b505af1158015612b8b573d5f803e3d5ffd5b505050505b612b9982614818565b6001600160a01b038216156103db5760408051606081018252610134546001600160701b0381168252600160701b81046001600160681b03166020830152600160d81b900464ffffffffff16918101919091525f612bf784836148b8565b90505f612c048484612fbb565b9050612c13858584848761312e565b5050505050565b6001600160a01b038083165f90815260fd6020526040902054168015801590612c4a57506001600160a01b038216155b15612c53578091505b6001600160a01b038216612c65578291505b5f612c6e610d8b565b90505f5b8151811015612c1357612c9f85838381518110612c9157612c91615bac565b602002602001015186613432565b5080612caa81615bd4565b915050612c72565b60018055565b610cfc8133614a4c565b5f80516020615f5383398151915282148015612d0557506001600160a01b0381165f9081526101356020526040902054600160701b90046001600160681b031615155b15612d235760405163433869fd60e11b815260040160405180910390fd5b6103db8282613b60565b5f610cec825490565b5f6115b08383614aa5565b5f805f80846060015164ffffffffff16421115612d9e57846040015164ffffffffff16856060015164ffffffffff161015612d7c575f612d90565b84604001518560600151612d909190615cd0565b64ffffffffff169150612dbf565b846040015164ffffffffff164203915042856060015164ffffffffff160390505b8185602001516001600160501b0316612dd89190615c73565b8186602001516001600160501b0316612df19190615c73565b935093505050915091565b612e05816128a9565b6001600160a01b038082165f9081526101356020908152604080832081516060808201845291546001600160701b0380821683526001600160681b03600160701b808404821685890190815264ffffffffff600160d81b958690048116878a01529a8d168a5261013d8952988790208751968701885254928316865282041695840186815291900490961692820192909252925190939091612ea8908390615cee565b6001600160681b039081169091526001600160a01b038681165f90815261013d6020908152604080832087518154898501518a8501516001600160701b039384166001600160d81b031990931692909217600160701b918a168202176001600160d81b0316600160d81b64ffffffffff938416810291909117909455968c168652610140855283862080546001600160a01b031916905583516060810185526101345492831681529682049097169386019390935290910490931692820192909252612f7b92508591908590859061312e565b6040515f906001600160a01b0386811691908616907f691c95c6dfadb8a9643f02b1ee3706982f7a9361ca534563e1f5944ae1471cac908490a450505050565b604080516060810182525f80825260208201819052918101919091526001600160a01b03831615610cec57506001600160a01b0382165f90815261013d60209081526040808320815160608101835290546001600160701b0381168252600160701b81046001600160681b031693820193909352600160d81b90920464ffffffffff169082018190529091036130595764ffffffffff421660408201525b5f61307c826040015164ffffffffff1662093a8062093a7f919091018190040290565b905061309c82602001516001600160681b0316835f0151855f015161373d565b6001600160681b0316602083015282516001600160701b031682524264ffffffffff8116604084015262093a8062093a7f909101819004025b80821015613126576020808401516001600160a01b0387165f90815261013e83526040808220868352909352919091206001600160681b03909116905561311f62093a8083615cbd565b91506130d5565b505092915050565b6001600160a01b0384166131475782915084935061320b565b6001600160a01b0384165f90815261013d6020908152604080832085518154938701519287015164ffffffffff16600160d81b026001600160d81b036001600160681b03909416600160701b026001600160d81b03199095166001600160701b039092169190911793909317919091169190911790556131d44262093a8062093a7f919091018190040290565b6020808501516001600160a01b0388165f90815261013e83526040808220948252939092529190206001600160681b039091169055505b5f61335883602001516001600160681b031685602001516001600160681b031684602001516001600160681b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a082318a6040518263ffffffff1660e01b815260040161329491906001600160a01b0391909116815260200190565b602060405180830381865afa1580156132af573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132d39190615c0c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561332f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133539190615c0c565b614acb565b6040805180820182526001600160401b039283168152610137545f1901831660208083019182526001600160a01b03909a165f90815261013c909a52919098209751885491518316600160401b026fffffffffffffffffffffffffffffffff19909216921691909117179095555050505050565b6133d68282611703565b156103db575f8281526097602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6001600160a01b038084165f90815260ff6020908152604080832093861683529281528282208351808501909452546001600160801b03808216808652600160801b9092041691840191909152909190801561354f57815160208301805161349b908390615d0e565b6001600160801b039081169091525f8085526001600160a01b03808a16825260ff60209081526040808420928b168085529282529092208651928701518416600160801b0292909316919091179091556134f791508583614b5a565b836001600160a01b0316856001600160a01b0316876001600160a01b03167fc1405953cccdad6b442e266c84d66ad671e2534c6584f8e6ef92802f7ad294d58460405161354691815260200190565b60405180910390a45b95945050505050565b6040516001600160a01b0380851660248301528316604482015260648101829052611d6a9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614b8a565b610137546040808301515f1983015f908152610138602052919091205464ffffffffff918216600160d81b9091049091160361366c575f1981015f908152610138602090815260409182902084518154928601519386015164ffffffffff16600160d81b026001600160d81b036001600160681b03909516600160701b026001600160d81b03199094166001600160701b039092169190911792909217929092161790556136df565b5f818152610138602090815260409182902084518154928601519386015164ffffffffff16600160d81b026001600160d81b036001600160681b03909516600160701b026001600160d81b03199094166001600160701b0390921691909117929092179290921617905560018101610137555b5080516101348054602084015160409094015164ffffffffff16600160d81b026001600160d81b036001600160681b03909516600160701b026001600160d81b03199092166001600160701b03909416939093171792909216179055565b5f835f0361374c57505f6115b0565b61375f826001600160701b031660581c90565b62ffffff16613777846001600160701b031660581c90565b62ffffff16101561378957505f6115b0565b5f6137a3604085811c62ffffff9081169186901c16615d2e565b62ffffff169050805f036137da576001600160401b03848116906137c990851687615c73565b6137d39190615c9e565b915061380d565b8060010361380957633b9aca006001600160401b03858116906137ff90861688615c73565b6137c99190615c9e565b5f91505b61381b633b9aca0086615c9e565b821015613826575f91505b509392505050565b6001600160a01b0381165f90815260018301602052604081205415156115b0565b64ffffffffff7f000000000000000000000000000000000000000000000000000000000000000016158061388a575061388860cb612d2d565b155b1561389157565b5f61389a610d8b565b90505f5b81518110156103db575f8282815181106138ba576138ba615bac565b6020908102919091018101516001600160a01b0381165f90815260ca83526040808220815160808101835290546001600160601b03811682526001600160501b03600160601b8204169582019590955264ffffffffff600160b01b8604811692820192909252600160d81b9094041660608401529092509061393b90612d41565b506001600160a01b0383165f90815260ca60205260409020805464ffffffffff60b01b1916600160b01b4264ffffffffff160217905590508015613983576139838282613cf8565b5050808061399090615bd4565b91505061389e565b7f000000000000000000000000000000000000000000000000000000000000000064ffffffffff165f036139d0576103db8282613cf8565b6001600160a01b0382165f90815260ca6020908152604091829020825160808101845290546001600160601b03811682526001600160501b03600160601b8204169282019290925264ffffffffff600160b01b8304811693820193909352600160d81b9091048216606082015290613a6c9082907f00000000000000000000000000000000000000000000000000000000000000001684614c5d565b6001600160a01b0383165f90815260ca602090815260409182902083518154928501519385015160609095015164ffffffffff908116600160d81b026001600160d81b0391909616600160b01b02166001600160b01b036001600160501b03909516600160601b026001600160b01b03199094166001600160601b03909216919091179290921792909216179190911790555050565b5f54610100900460ff16613b285760405162461bcd60e51b81526004016110ec90615d4a565b613b30614e1b565b565b5f54610100900460ff16613b585760405162461bcd60e51b81526004016110ec90615d4a565b613b30614e41565b613b6a8282611703565b6103db575f8281526097602090815260408083206001600160a01b03851684529091529020805460ff19166001179055613ba13390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b801580613c5d5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015613c37573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613c5b9190615c0c565b155b613cc85760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b60648201526084016110ec565b6040516001600160a01b038316602482015260448101829052610d8690849063095ea7b360e01b9060640161358c565b805f03613d03575050565b60408051606081018252610134546001600160701b038116808352600160701b82046001600160681b031660208401819052600160d81b90920464ffffffffff169290930191909152805f03613dad576001600160a01b0384165f90815260ca602052604081208054859290613d839084906001600160601b0316615d95565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555050505050565b5f613dc1836001600160701b031660401c90565b6001600160a01b0386165f90815260fe6020908152604080832065ffffffffffff85168452825291829020825180840190935254600160401b90046001600160c01b0316908201526001600160401b034281168252919250908416908184613e31670de0b6b3a764000089615c73565b613e3b9190615c9e565b613e459190615db5565b81602001818151613e569190615de7565b6001600160c01b039081169091526001600160a01b039098165f90815260fe6020908152604080832065ffffffffffff909716835295815294902082519490920151909716600160401b026001600160401b03909316929092179091555050505050565b60408051606081018252610134546001600160701b0381168252600160701b81046001600160681b031660208301819052600160d81b90910464ffffffffff1692820192909252905f908310613f2557505f61013b8190556020820152670de0b6b3a7640000613fb9565b61013b545f90613f3d670de0b6b3a764000086615c73565b613f479190615c60565b905082602001516001600160681b031681613f629190615c9e565b613f6d906001615cbd565b91508083602001516001600160681b031683613f899190615c73565b613f939190615c60565b61013b55602083018051859190613fab908390615cee565b6001600160681b0316905250505b5f613fcc82670de0b6b3a7640000615c60565b8351909150613fe4906001600160701b031682614e67565b6001600160701b0316835264ffffffffff42166040840152611d6a836135c3565b6001600160a01b038281165f81815260ff602090815260408083209486168352938152838220845160808101865281546001600160801b03808216838901908152600160801b90920416606080840191909152908252865180880188526001909301546001600160401b0381168452600160401b90046001600160c01b03168385015281840192909252938352610135825284832085519182018652546001600160701b038116808352600160701b82046001600160681b0316938301849052600160d81b90910464ffffffffff1691909501529092908084036140f757505051516001600160801b03169050610cec565b5f61410b836001600160701b031660401c90565b6020858101518101516001600160a01b0389165f90815260fe8352604080822065ffffffffffff9590951680835294909352918220549293506001600160401b038616926141699190600160401b90046001600160c01b0316615e07565b6001600160a01b0389165f90815260fe602052604081206001600160c01b0392909216925090633b9aca0090826141a1876001615cbd565b815260208101919091526040015f20546141cb9190600160401b90046001600160c01b0316615c9e565b90506141df670de0b6b3a764000084615c73565b6141e98284615cbd565b6141f39087615c73565b6141fd9190615c9e565b87515161421391906001600160801b0316615cbd565b9a9950505050505050505050565b6001600160a01b0381165f90815261013560209081526040808320815160608101835290546001600160701b0381168252600160701b81046001600160681b0316938201849052600160d81b900464ffffffffff169181019190915290820361428c57505f92915050565b6001600160a01b0383165f90815261013c60209081526040918290208251808401845290546001600160401b038082168352600160401b9091041691810191909152908201514264ffffffffff909116036142f257516001600160401b03169392505050565b6001600160a01b038085165f908152610140602052604081205490911690811561431c578161431e565b855b6020840151845160408701519293506001600160401b039182169291169064ffffffffff1662093a8062093a7f8201819004025f5b6101008110156144bf5742821115614369574291505b82820384028a019950428203156144bf57604051627eeac760e11b81526001600160a01b038781166004830152602482018490525f917f00000000000000000000000000000000000000000000000000000000000000009091169062fdd58e90604401602060405180830381865afa1580156143e7573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061440b9190615c0c565b60405163bd85b03960e01b8152600481018590529091505f906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063bd85b03990602401602060405180830381865afa158015614473573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906144979190615c0c565b90506144a7898c84848b89614f1f565b975095509293505062093a8083019150600101614353565b50876040015164ffffffffff16420389816144dc576144dc615c8a565b049a9950505050505050505050565b5f6115b0836001600160a01b03841661502d565b5f6115b0836001600160a01b038416615117565b61451c836128a9565b6040805160608082018352610134546001600160701b0380821684526001600160681b03600160701b808404821660208088019190915264ffffffffff600160d81b958690048116888a01526001600160a01b038c165f90815261013583528981208a51808a018c52905496871681529386048516848401908152969095041682890152875195860188528386528501839052958401919091529051929392168511156145d45781602001516001600160681b031694505b845f036145f4576040516352c6c20960e11b815260040160405180910390fd5b602080840180516001600160681b0390889003811690915264ffffffffff421660408087019190915284830180518990039092169091526001600160a01b038089165f9081526101409093529120541680156146c5576001600160a01b0381165f90815261013d6020908152604091829020825160608101845290546001600160701b0381168252600160701b81046001600160681b0316928201838152600160d81b90910464ffffffffff169382019390935293508791906146b8908390615cee565b6001600160681b03169052505b6146ce846135c3565b6001600160a01b0387165f908152610135602090815260409182902085518154928701519387015164ffffffffff16600160d81b026001600160d81b036001600160681b03909516600160701b026001600160d81b03199094166001600160701b0390921691909117929092179290921617905561474f878285858861312e565b61013354614767906001600160a01b03168688614b5a565b846001600160a01b0316876001600160a01b03167f9b1bfa7fa9ee420a16e124f794c35ac9f90472acc99140eb2f6447c714cad8eb886040516147ac91815260200190565b60405180910390a3866001600160a01b03167f5fa7d0e13a31540b6d42936e522173de31fa0c53aa5aff71e63c60fe02b2b50e84602001515f6040516148079291906001600160681b03929092168252602082015260400190565b60405180910390a250505050505050565b61482061384f565b6001600160a01b03811615610cfc575f614838610d8b565b90505f5b815181101561487a576148688383838151811061485b5761485b615bac565b6020026020010151615163565b8061487281615bd4565b91505061483c565b50614883611995565b90505f5b8151811015610d86576148a68383838151811061485b5761485b615bac565b806148b081615bd4565b915050614887565b60408051606080820183525f80835260208084018290529284018190526001600160a01b0386168152610135835283812084519283018552546001600160701b038116808452600160701b82046001600160681b0316948401859052600160d81b90910464ffffffffff169483019490945284519193909261493c9290919061373d565b905081602001516001600160681b0316816001600160681b0316146149bb57836001600160a01b03167f5fa7d0e13a31540b6d42936e522173de31fa0c53aa5aff71e63c60fe02b2b50e828385602001516149979190615cee565b604080516001600160681b0393841681529290911660208301520160405180910390a25b6001600160681b03908116602080840191825293516001600160701b03908116845264ffffffffff42811660408087019182526001600160a01b039098165f908152610135909752969095208451815493519751909616600160d81b026001600160d81b0397909416600160701b026001600160d81b03199093169590911694909417179390931692909217905590565b614a568282611703565b6103db57614a63816153fd565b614a6e83602061540f565b604051602001614a7f929190615e49565b60408051601f198184030181529082905262461bcd60e51b82526110ec91600401615ebd565b5f825f018281548110614aba57614aba615bac565b905f5260205f200154905092915050565b5f845f03614ae2575067058d15e17628000061354f565b600a60048702048215614b1657600a8386860281614b0257614b02615c8a565b0460060281614b1357614b13615c8a565b04015b8686820281614b2757614b27615c8a565b04905085811115614b355750845b85670de0b6b3a7640000820281614b4e57614b4e615c8a565b04979650505050505050565b6040516001600160a01b038316602482015260448101829052610d8690849063a9059cbb60e01b9060640161358c565b5f614bde826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166155a49092919063ffffffff16565b905080515f1480614bfe575080806020019051810190614bfe9190615eef565b610d865760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016110ec565b8251614c72906001600160601b031682615cbd565b5f8452606084015190915064ffffffffff164210614cf657614c9c614c978383615c9e565b6155ba565b6001600160501b031660208401819052614cb7908390615c73565b614cc19082615c60565b6001600160601b031683524264ffffffffff81166040850152614ce5908390615cbd565b64ffffffffff166060840152505050565b5f82846060015164ffffffffff16614d0e9190615c60565b614d189042615c60565b90505f8185602001516001600160501b0316614d349190615c73565b9050614d4183600a615c73565b614d4c826009615c73565b11614e005784604001518560600151614d659190615cd0565b64ffffffffff1685602001516001600160501b0316614d849190615c73565b614d8e9084615cbd565b9250614d9d614c978585615c9e565b6001600160501b031660208601819052614db8908590615c73565b614dc29084615c60565b6001600160601b031685524264ffffffffff81166040870152614de6908590615cbd565b64ffffffffff908116606087015242166040860152612c13565b614e0983615625565b6001600160601b031685525050505050565b5f54610100900460ff16612cb25760405162461bcd60e51b81526004016110ec90615d4a565b5f54610100900460ff16613b305760405162461bcd60e51b81526004016110ec90615d4a565b5f80614e738460581c90565b90505f614e858560401c62ffffff1690565b90506001600160401b038581169085165f03614eaf5750506001015f670de0b6b3a7640000614f08565b633b9aca00670de0b6b3a76400006001600160401b0387168302041015614eef5760019190910190633b9aca006001600160401b03861690910204614f08565b670de0b6b3a76400006001600160401b03861682020490505b605883901b604083901b0181019695505050505050565b610137545f9081905f19015b80851015614f745760018186018101901c5f8181526101386020526040902054600160d81b900464ffffffffff168510614f6757809550614f6e565b6001810391505b50614f2b565b505f84815261013860209081526040808320815160608101835290546001600160701b038116808352600160701b82046001600160681b0390811684870152600160d81b90920464ffffffffff1693830193909352928b01518b51919493614fdf939116919061373d565b90505f6001600160a01b038b16614ff65781615000565b6150008b8761568c565b905061501c818385602001516001600160681b03168c8c614acb565b9b969a509598505050505050505050565b5f8181526001830160205260408120548015615107575f61504f600183615c60565b85549091505f9061506290600190615c60565b90508181146150c1575f865f01828154811061508057615080615bac565b905f5260205f200154905080875f0184815481106150a0576150a0615bac565b5f918252602080832090910192909255918252600188019052604090208390555b85548690806150d2576150d2615f0e565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610cec565b5f915050610cec565b5092915050565b5f81815260018301602052604081205461515c57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610cec565b505f610cec565b6001600160a01b038281165f90815260ff602090815260408083209385168352928152828220835160808101855281546001600160801b03808216838801908152600160801b9092041660608301528152845180860186526001909201546001600160401b03811683526001600160c01b03600160401b9091041682840152918201526101345490921c65ffffffffffff1690507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03160361532e576001600160a01b038481165f9081526101406020908152604091829020548251606081018452610134546001600160701b0381168252600160701b81046001600160681b031693820193909352600160d81b90920464ffffffffff16928201929092526152a1929190911690612fbb565b508151515f906001600160801b03166152ba8686614005565b818103925014615328575f6152ce86614221565b845180516001600160801b03670de0b6b3a7640000868502049182011690915290915080831115615325576153257f0000000000000000000000000000000000000000000000000000000000000000828503613998565b50505b50615348565b6153388484614005565b82516001600160801b0390911690525b6001600160a01b039283165f81815260fe6020908152604080832065ffffffffffff90951683529381528382208451808601865290546001600160c01b03600160401b91829004811683850152878401838152426001600160401b0390811690945299909816845260ff83528584209484529382529390912093518051908201516001600160801b03908116600160801b02911617845594518051950151909316909202929091169190911760019190910155565b6060610cec6001600160a01b03831660145b60605f61541d836002615c73565b615428906002615cbd565b6001600160401b0381111561543f5761543f6159ec565b6040519080825280601f01601f191660200182016040528015615469576020820181803683370190505b509050600360fc1b815f8151811061548357615483615bac565b60200101906001600160f81b03191690815f1a905350600f60fb1b816001815181106154b1576154b1615bac565b60200101906001600160f81b03191690815f1a9053505f6154d3846002615c73565b6154de906001615cbd565b90505b6001811115615555576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061551257615512615bac565b1a60f81b82828151811061552857615528615bac565b60200101906001600160f81b03191690815f1a90535060049490941c9361554e81615f22565b90506154e1565b5083156115b05760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016110ec565b60606155b284845f8561572b565b949350505050565b5f6001600160501b038211156156215760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201526530206269747360d01b60648201526084016110ec565b5090565b5f6001600160601b038211156156215760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201526536206269747360d01b60648201526084016110ec565b6001600160a01b0382165f90815261013d6020526040812054600160d81b900464ffffffffff165b808311156156fd576001600160a01b0384165f90815261013e6020908152604080832086845290915290205480156156ef579150610cec9050565b62093a8084039350506156b4565b5050506001600160a01b03165f90815261013d6020526040902054600160701b90046001600160681b031690565b60608247101561578c5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016110ec565b5f80866001600160a01b031685876040516157a79190615f37565b5f6040518083038185875af1925050503d805f81146157e1576040519150601f19603f3d011682016040523d82523d5f602084013e6157e6565b606091505b50915091506157f787838387615802565b979650505050505050565b606083156158705782515f03615869576001600160a01b0385163b6158695760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016110ec565b50816155b2565b6155b283838151156158855781518083602001fd5b8060405162461bcd60e51b81526004016110ec9190615ebd565b6001600160a01b0381168114610cfc575f80fd5b80356158be8161589f565b919050565b5f80604083850312156158d4575f80fd5b8235915060208301356158e68161589f565b809150509250929050565b5f60208284031215615901575f80fd5b81356001600160e01b0319811681146115b0575f80fd5b5f8060408385031215615929575f80fd5b82356159348161589f565b915060208301356158e68161589f565b5f8060408385031215615955575f80fd5b82356159608161589f565b946020939093013593505050565b5f6020828403121561597e575f80fd5b81356115b08161589f565b5f60208284031215615999575f80fd5b5035919050565b602080825282518282018190525f9190848201906040850190845b818110156159e05783516001600160a01b0316835292840192918401916001016159bb565b50909695505050505050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f830112615a0f575f80fd5b813560206001600160401b0380831115615a2b57615a2b6159ec565b8260051b604051601f19603f83011681018181108482111715615a5057615a506159ec565b604052938452858101830193838101925087851115615a6d575f80fd5b83870191505b848210156157f757615a84826158b3565b83529183019190830190615a73565b5f60208284031215615aa3575f80fd5b81356001600160401b03811115615ab8575f80fd5b6155b284828501615a00565b5f8060408385031215615ad5575f80fd5b8235615ae08161589f565b915060208301356001600160401b03811115615afa575f80fd5b615b0685828601615a00565b9150509250929050565b5f805f60608486031215615b22575f80fd5b8335615b2d8161589f565b92506020840135615b3d8161589f565b91506040840135615b4d8161589f565b809150509250925092565b5f8060408385031215615b69575f80fd5b50508035926020909101359150565b5f805f60608486031215615b8a575f80fd5b8335615b958161589f565b9250602084013591506040840135615b4d8161589f565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f60018201615be557615be5615bc0565b5060010190565b6001600160681b0381811683821601908082111561511057615110615bc0565b5f60208284031215615c1c575f80fd5b5051919050565b5f60208284031215615c33575f80fd5b81516115b08161589f565b5f8060408385031215615c4f575f80fd5b505080516020909101519092909150565b81810381811115610cec57610cec615bc0565b8082028115828204841417610cec57610cec615bc0565b634e487b7160e01b5f52601260045260245ffd5b5f82615cb857634e487b7160e01b5f52601260045260245ffd5b500490565b80820180821115610cec57610cec615bc0565b64ffffffffff82811682821603908082111561511057615110615bc0565b6001600160681b0382811682821603908082111561511057615110615bc0565b6001600160801b0381811683821601908082111561511057615110615bc0565b62ffffff82811682821603908082111561511057615110615bc0565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160601b0381811683821601908082111561511057615110615bc0565b6001600160c01b03828116828216818102831692918115828504821417615dde57615dde615bc0565b50505092915050565b6001600160c01b0381811683821601908082111561511057615110615bc0565b6001600160c01b0382811682821603908082111561511057615110615bc0565b5f5b83811015615e41578181015183820152602001615e29565b50505f910152565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f8351615e80816017850160208801615e27565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351615eb1816028840160208801615e27565b01602801949350505050565b602081525f8251806020840152615edb816040850160208701615e27565b601f01601f19169190910160400192915050565b5f60208284031215615eff575f80fd5b815180151581146115b0575f80fd5b634e487b7160e01b5f52603160045260245ffd5b5f81615f3057615f30615bc0565b505f190190565b5f8251615f48818460208701615e27565b919091019291505056fe8d4998b5742dab4ffcf0a281dc749862b71ae54ba53b035bfb1d3dbc23ddc35d0f51adb3f49e4a9bbb17b3783f025995eaf8c24be2c8eefff214bdfda05ef94da26469706673582212201d56ae33c2a8e80b2c0139a93f2ced33f4ee227a5a88aca8fe5aaa52d95155f564736f6c63430008140033000000000000000000000000365accfca291e7d3914637abf1f7635db165bb09000000000000000000000000ec6b8a3f3605b083f7044c0f31f2cac0caf1d469000000000000000000000000d766f2b87de4b08c2239580366e49710180aba02000000000000000000000000c8b194925d55d5de9555ad1db74c149329f71def
Deployed Bytecode
0x608060405234801561000f575f80fd5b50600436106103c9575f3560e01c8063818c371511610200578063d1b5893c1161011f578063dffaf449116100b4578063f38e412811610084578063f38e412814610c4c578063f593a62a14610c7a578063fbb4ad5b14610c8e578063fdc5aa5d14610c96578063ff9fe67214610ca9575f80fd5b8063dffaf44914610b54578063e162402f14610b67578063e75c9a4e14610b7a578063f305ce4714610b84575f80fd5b8063d547741f116100ef578063d547741f14610b08578063d5a3aa7c14610b1b578063dae254dd14610b2e578063db02794614610b41575f80fd5b8063d1b5893c14610a9b578063d296d1f114610aa5578063d2ca211514610ab8578063d4570c1c14610af5575f80fd5b8063a6f19c8411610195578063c0c53b8b11610165578063c0c53b8b14610a02578063c0c7a7b414610a15578063c55dae6314610a5f578063cc64278414610a73575f80fd5b8063a6f19c8414610986578063a972985e146109d3578063ac210cc7146109e6578063ad347817146109fa575f80fd5b80639a2a42b8116101d05780639a2a42b81461094f5780639b4bf63e146109625780639d0d5bbd1461096c578063a217fddf1461097f575f80fd5b8063818c3715146108db578063838163ff1461090257806391d1485414610915578063982b0aa814610928575f80fd5b806336568abe116102ec5780636641d9a0116102815780636e553f65116102515780636e553f651461088e57806370a08231146108a15780637db4e28f146108b457806380f55605146108c7575f80fd5b80636641d9a0146107c15780636720a1201461083f5780636be2e80d146108675780636d750d801461087a575f80fd5b80634c3da2da116102bc5780634c3da2da146107105780634e71d92d1461077c5780635c8254301461078457806361d027b3146107ad575f80fd5b806336568abe14610630578063383d5dc81461064357806338d52e0f1461066a57806348e5d9f81461067e575f80fd5b80631f8507161161036257806330ae4bba1161033257806330ae4bba1461058c57806331d7a262146105a157806332ff6afb146105c957806333eda141146105dc575f80fd5b80631f8507161461051d57806321c0b34214610544578063248a9ca3146105575780632f2ff15d14610579575f80fd5b806315dec2951161039d57806315dec2951461049f57806316d8887a146104ca57806318160ddd146104f15780631e83409a1461050a575f80fd5b8062f714ce146103cd57806301ffc9a7146103e157806307546172146104095780630c9cbf0e14610448575b5f80fd5b6103df6103db3660046158c3565b5050565b005b6103f46103ef3660046158f1565b610cbc565b60405190151581526020015b60405180910390f35b6104307f000000000000000000000000c8b194925d55d5de9555ad1db74c149329f71def81565b6040516001600160a01b039091168152602001610400565b610491610456366004615918565b6001600160a01b038281165f90815260ff6020908152604080832093851683529290522054600160801b90046001600160801b031692915050565b604051908152602001610400565b6104916104ad366004615944565b61013e60209081525f928352604080842090915290825290205481565b6104917f5e17fc5225d4a099df75359ce1f405503ca79498a8dc46a7d583235a0ee45c1681565b61013454600160701b90046001600160681b0316610491565b6103df61051836600461596e565b610cf2565b6104307f000000000000000000000000ec6b8a3f3605b083f7044c0f31f2cac0caf1d46981565b6103df610552366004615918565b610cff565b610491610565366004615989565b5f9081526097602052604090206001015490565b6103df6105873660046158c3565b610d62565b610594610d8b565b60405161040091906159a0565b6105b46105af36600461596e565b610e34565b60408051928352602083019190915201610400565b6103df6105d736600461596e565b610eb3565b6106106105ea36600461596e565b61013c6020525f90815260409020546001600160401b0380821691600160401b90041682565b604080516001600160401b03938416815292909116602083015201610400565b6103df61063e3660046158c3565b611080565b6104307f000000000000000000000000365accfca291e7d3914637abf1f7635db165bb0981565b61013354610430906001600160a01b031681565b6106d161068c36600461596e565b60ca6020525f90815260409020546001600160601b038116906001600160501b03600160601b8204169064ffffffffff600160b01b8204811691600160d81b90041684565b604080516001600160601b0390951685526001600160501b03909316602085015264ffffffffff91821692840192909252166060820152608001610400565b61075561071e366004615944565b60fe60209081525f92835260408084209091529082529020546001600160401b03811690600160401b90046001600160c01b031682565b604080516001600160401b0390931683526001600160c01b03909116602083015201610400565b6103df6110ff565b61043061079236600461596e565b6101406020525f90815260409020546001600160a01b031681565b61012f54610430906001600160a01b031681565b61080b6107cf366004615989565b6101386020525f90815260409020546001600160701b03811690600160701b81046001600160681b031690600160d81b900464ffffffffff1683565b604080516001600160701b0390941684526001600160681b03909216602084015264ffffffffff1690820152606001610400565b61043061084d36600461596e565b60fd6020525f90815260409020546001600160a01b031681565b6103df610875366004615a93565b61110a565b6104915f80516020615f7383398151915281565b6103df61089c3660046158c3565b61118c565b6104916108af36600461596e565b61153f565b6103df6108c2366004615944565b6115b7565b61013054610430906001600160a01b031681565b6104307f000000000000000000000000d766f2b87de4b08c2239580366e49710180aba0281565b6103df610910366004615ac4565b611691565b6103f46109233660046158c3565b611703565b6104917f24ba51fc201891c1803eeafedeae076c0a88d453c20b1073528aa34d0cf55b7981565b6103df61095d36600461596e565b61172d565b6104916101395481565b6103df61097a366004615989565b61192a565b6104915f81565b610131546109ac906001600160a01b03811690600160a01b90046001600160401b031682565b604080516001600160a01b0390931683526001600160401b03909116602083015201610400565b6103df6109e136600461596e565b61197b565b61013a54610430906001600160a01b031681565b610594611995565b6103df610a10366004615b10565b611a39565b61080b610a2336600461596e565b61013d6020525f90815260409020546001600160701b03811690600160701b81046001600160681b031690600160d81b900464ffffffffff1683565b61013254610430906001600160a01b031681565b610430610a8136600461596e565b60c96020525f90815260409020546001600160a01b031681565b6104916101375481565b6105b4610ab3366004615b58565b611d70565b610adf7f0000000000000000000000000000000000000000000000000000000000093a8081565b60405164ffffffffff9091168152602001610400565b610491610b03366004615918565b612196565b6103df610b163660046158c3565b61226a565b610491610b2936600461596e565b61228e565b6103df610b3c36600461596e565b612298565b6103df610b4f36600461596e565b6122f6565b6103df610b62366004615918565b612493565b6103df610b75366004615b78565b612584565b61049161013b5481565b610c02610b92366004615918565b60ff60209081525f92835260408084208252918352918190208151808301835281546001600160801b038082168352600160801b909104168185015282518084019093526001909101546001600160401b0381168352600160401b90046001600160c01b03169282019290925282565b60405161040092919082516001600160801b039081168252602093840151168382015281516001600160401b031660408201529101516001600160c01b0316606082015260800190565b6103f4610c5a366004615918565b61013f60209081525f928352604080842090915290825290205460ff1681565b6104915f80516020615f5383398151915281565b6103df6125b9565b6103df610ca436600461596e565b6125fa565b6103df610cb7366004615918565b612786565b5f6001600160e01b03198216637965db0b60e01b1480610cec57506301ffc9a760e01b6001600160e01b03198316145b92915050565b610cfc815f610cff565b50565b610d07612850565b6001600160a01b0382163314801590610d2857506001600160a01b03811615155b15610d4657604051630894de8d60e01b815260040160405180910390fd5b610d4f826128a9565b610d598282612c1a565b6103db60018055565b5f82815260976020526040902060010154610d7c81612cb8565b610d868383612cc2565b505050565b60605f610d9860cb612d2d565b9050806001600160401b03811115610db257610db26159ec565b604051908082528060200260200182016040528015610ddb578160200160208202803683370190505b5091505f5b81811015610e2f57610df360cb82612d36565b838281518110610e0557610e05615bac565b6001600160a01b039092166020928302919091019091015280610e2781615bd4565b915050610de0565b505090565b6001600160a01b0381165f90815260ca60209081526040808320815160808101835290546001600160601b03811682526001600160501b03600160601b8204169382019390935264ffffffffff600160b01b8404811692820192909252600160d81b9092041660608201528190610eaa90612d41565b91509150915091565b6001600160a01b0381165f90815261013f602090815260408083203380855292529091205460ff16610ef85760405163a0def43760e01b815260040160405180910390fd5b6001600160a01b038082165f908152610140602052604090205481169083168103610f365760405163097000d560e41b815260040160405180910390fd5b6001600160a01b03811615610f5457610f4f8183612dfc565b610f5d565b610f5d826128a9565b6001600160a01b038281165f9081526101406020908152604080832080546001600160a01b03191694881694909417909355610135815282822083516060808201865291546001600160701b038082168352600160701b8083046001600160681b0390811685880152600160d81b9384900464ffffffffff908116868b015289519687018a5261013454938416875291830416958501959095520490921693810193909352919061100e8683612fbb565b90508260200151816020018181516110269190615bec565b6001600160681b031690525061103f858785848661312e565b6040516001600160a01b03808816915f918816907f691c95c6dfadb8a9643f02b1ee3706982f7a9361ca534563e1f5944ae1471cac908390a4505050505050565b6001600160a01b03811633146110f55760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084015b60405180910390fd5b6103db82826133cc565b33610cfc815f610cff565b611112612850565b3361111c816128a9565b6001600160a01b038082165f90815260fd6020526040902054168061113e5750805b5f5b83518110156111805761116d8385838151811061115f5761115f615bac565b602002602001015184613432565b508061117881615bd4565b915050611140565b505050610cfc60018055565b6111a35f80516020615f5383398151915282611703565b156111c15760405163433869fd60e11b815260040160405180910390fd5b6101335433906001600160a01b031660018401611243576040516370a0823160e01b81526001600160a01b0383811660048301528216906370a0823190602401602060405180830381865afa15801561121c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112409190615c0c565b93505b835f03611263576040516322c1ccd560e21b815260040160405180910390fd5b6112786001600160a01b038216833087613558565b611281836128a9565b6040805160608082018352610134546001600160701b038082168452600160701b8083046001600160681b039081166020808801918252600160d81b9586900464ffffffffff908116898b01526001600160a01b038d165f90815261013583528a81208b51808b018d52905497881681529587049094168583015295909404909416828801528651948501875280855291840182905294830152805192939288919061132e908390615bec565b6001600160681b031690525064ffffffffff4216604084015260208201805188919061135b908390615bec565b6001600160681b03169052506001600160a01b038087165f9081526101406020526040902054168015611403576001600160a01b0381165f90815261013d6020908152604091829020825160608101845290546001600160701b0381168252600160701b81046001600160681b0316928201838152600160d81b90910464ffffffffff169382019390935293508991906113f6908390615bec565b6001600160681b03169052505b61140c846135c3565b6001600160a01b0387165f908152610135602090815260409182902085518154928701519387015164ffffffffff16600160d81b026001600160d81b036001600160681b03909516600160701b026001600160d81b03199094166001600160701b0390921691909117929092179290921617905561148d878285858861312e565b866001600160a01b0316866001600160a01b03167f5548c837ab068cf56a2c2479df0882a4922fd203edb7517321831d95078c5f628a6040516114d291815260200190565b60405180910390a3866001600160a01b03167f5fa7d0e13a31540b6d42936e522173de31fa0c53aa5aff71e63c60fe02b2b50e84602001515f60405161152d9291906001600160681b03929092168252602082015260400190565b60405180910390a25050505050505050565b6001600160a01b0381165f90815261013560209081526040808320815160608101835290546001600160701b03808216808452600160701b83046001600160681b0316958401869052600160d81b90920464ffffffffff16938301939093526101345491936115b09390921661373d565b9392505050565b336115c360cb8461382e565b6115e05760405163ad2882d360e01b815260040160405180910390fd5b6001600160a01b038381165f90815260c9602052604090205481169082161461161c5760405163af216a6b60e01b815260040160405180910390fd5b8115611637576116376001600160a01b038416823085613558565b61163f61384f565b6116498383613998565b826001600160a01b03167f4f7fd5c9e17300a4800fd572ea53fc291e2ee7470d73346d16b357faee4e72108360405161168491815260200190565b60405180910390a2505050565b611699612850565b6116a2826128a9565b6001600160a01b038083165f90815260fd602052604090205416806116c45750815b5f5b82518110156116f8576116e58484838151811061115f5761115f615bac565b50806116f081615bd4565b9150506116c6565b50506103db60018055565b5f9182526097602090815260408084206001600160a01b0393909316845291905290205460ff1690565b5f61173781612cb8565b6101325460408051632e7dc6af60e01b815290516001600160a01b0392831692851691632e7dc6af9160048083019260209291908290030181865afa158015611782573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117a69190615c23565b6001600160a01b0316146117cd57604051632124403760e11b815260040160405180910390fd5b61013a546001600160a01b03163081148015906118ba5750826001600160a01b031663d48532b36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611821573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118459190615c23565b6001600160a01b0316816001600160a01b031663d48532b36040518163ffffffff1660e01b8152600401602060405180830381865afa15801561188a573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906118ae9190615c23565b6001600160a01b031614155b156118d8576040516302bae16b60e01b815260040160405180910390fd5b61013a80546001600160a01b0319166001600160a01b0385811691821790925560405190918316907fe6ed57be293efa66c0a505ccdf4018974586d424d796b8ae52745cf0a1f2e2d3905f90a3505050565b5f61193481612cb8565b61013980549083905560408051828152602081018590527fbf7572abbb7816b05b5dd2f50fc9e818813c1d4c6f51e99e7ae15b5604fa0396910160405180910390a1505050565b611983612850565b61198c816128a9565b610cfc60018055565b60605f6119a260cd612d2d565b9050806001600160401b038111156119bc576119bc6159ec565b6040519080825280602002602001820160405280156119e5578160200160208202803683370190505b5091505f5b81811015610e2f576119fd60cd82612d36565b838281518110611a0f57611a0f615bac565b6001600160a01b039092166020928302919091019091015280611a3181615bd4565b9150506119ea565b5f54610100900460ff1615808015611a5757505f54600160ff909116105b80611a705750303b158015611a7057505f5460ff166001145b611ad35760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016110ec565b5f805460ff191660011790558015611af4575f805461ff0019166101001790555b611afc613b02565b611b04613b32565b611b0e5f33613b60565b611b255f80516020615f7383398151915233613b60565b61012f80546001600160a01b038087166001600160a01b0319928316811790935561013080548783169084161790556101318054918616919092161790556040805163c55dae6360e01b8152905163c55dae63916004808201926020929091908290030181865afa158015611b9c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bc09190615c23565b6101325f6101000a8154816001600160a01b0302191690836001600160a01b03160217905550836001600160a01b031663a8694e576040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c22573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c469190615c23565b61013380546001600160a01b03929092166001600160a01b031992831617905561013a805490911630179055670de0b6b3a764000061013480546001600160701b039283166cffffffffffffffffffffffffff60701b90911617600160d81b4264ffffffffff908116820292909217928390555f80526101386020527f466a001727fe4c50af81de09fe9d15b89f88e442506e33af81822399cd821bb080546001600160d81b039585166001600160d81b031990911617600160701b8086046001600160681b031602179490941692819004909116021790556001610137558015611d6a575f805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050565b5f807f5e17fc5225d4a099df75359ce1f405503ca79498a8dc46a7d583235a0ee45c16611d9c81612cb8565b611da55f6128a9565b61012f54610139546040805163b4eae1cb60e01b815290516001600160a01b0390931692839163b4eae1cb9160048083019260209291908290030181865afa158015611df3573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e179190615c0c565b10611e355760405163bf87c7d560e01b815260040160405180910390fd5b610139546040516271691b60e21b81525f916001600160a01b038416916301c5a46c91611e689160040190815260200190565b6040805180830381865afa158015611e82573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ea69190615c3e565b915081905087811115611eb65750865b610133546101305461013a546040516370a0823160e01b81523060048201526001600160a01b0393841693928316929091169083906370a0823190602401602060405180830381865afa158015611f0f573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f339190615c0c565b985088841115611f41578893505b611f556001600160a01b038416835f613be5565b611f696001600160a01b0384168386613be5565b6040516368674c7d60e11b8152600481018590526001600160a01b038281166024830152604482018c905283169063d0ce98fa9060640160408051808303815f875af1158015611fbb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fdf9190615c3e565b506040516370a0823160e01b81523060048201529098506001600160a01b038416906370a0823190602401602060405180830381865afa158015612025573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120499190615c0c565b612053908a615c60565b60408051828152602081018b9052919a507f253e5385159062a101837d58c10ad4694c58979ebc3ba6b5cb2cbba2fe461692910160405180910390a1610132546001600160a01b03908116908216301461217457604051630ea598cb60e41b8152600481018a90526001600160a01b0383169063ea598cb0906024016020604051808303815f875af11580156120eb573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061210f9190615c0c565b9850816001600160a01b031663d48532b36040518163ffffffff1660e01b8152600401602060405180830381865afa15801561214d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121719190615c23565b90505b61217e818a613cf8565b6121878a613eba565b50505050505050509250929050565b5f7f000000000000000000000000365accfca291e7d3914637abf1f7635db165bb096001600160a01b0316826001600160a01b031603612259576001600160a01b038084165f90815260ff602090815260408083209386168352929052908120546001600160801b0316908161220c8686614005565b6122169190615c60565b90505f6122228661228e565b90505f670de0b6b3a76400006122388385615c73565b6122429190615c9e565b905061224e8185615cbd565b945050505050610cec565b6122638383614005565b9050610cec565b5f8281526097602052604090206001015461228481612cb8565b610d8683836133cc565b5f610cec82614221565b335f81815260fd602052604080822080546001600160a01b031981166001600160a01b038781169182179093559251911692839185917f49ddedcc7960d57ef16bbd5dda435520c8a203a051b3eb1a02f7e71e77478bf091a4505050565b5f80516020615f7383398151915261230d81612cb8565b61231860cb8361382e565b6123355760405163ad2882d360e01b815260040160405180910390fd5b6001600160a01b0382165f90815260ca60209081526040808320815160808101835290546001600160601b03811682526001600160501b03600160601b8204169382019390935264ffffffffff600160b01b8404811692820192909252600160d81b90920416606082015290806123ab83612d41565b915091507f0000000000000000000000000000000000000000000000000000000000093a8064ffffffffff16835f01516001600160601b031610156123ee575f83525b82516001600160601b0316820181011561241b57604051630e6d89d360e21b815260040160405180910390fd5b50612429905060cb846144eb565b506001600160a01b0383165f90815260c96020526040902080546001600160a01b031916905561245a60cd846144ff565b506040516001600160a01b038416907fbfa4256e0ed8b426ac2df0a3469f79ee315552c50c46d123cfbc165252d8550e905f90a2505050565b5f80516020615f738339815191526124aa81612cb8565b6001600160a01b0382166124d157604051632fea089160e11b815260040160405180910390fd5b6124dc60cb8461382e565b156124fa57604051638599b12960e01b815260040160405180910390fd5b61250560cb846144ff565b506001600160a01b038381165f90815260c96020526040902080546001600160a01b03191691841691909117905561253e60cd846144eb565b50816001600160a01b0316836001600160a01b03167fd58451dda05155bb82ebdd6dfb79317f4ad9e8a480a422409a044b4c02286ed160405160405180910390a3505050565b7f24ba51fc201891c1803eeafedeae076c0a88d453c20b1073528aa34d0cf55b796125ae81612cb8565b611d6a848484614513565b335f81815261014060205260409020546001600160a01b0316806125f0576040516306bc241560e31b815260040160405180910390fd5b6103db8183612dfc565b5f80516020615f5383398151915261261181612cb8565b336001600160a01b03831681900361263c576040516346023c5b60e01b815260040160405180910390fd5b6001600160a01b038181165f9081526101406020526040902054161561267557604051630b0a071f60e31b815260040160405180910390fd5b6001600160a01b038082165f90815261013f602090815260408083209387168352929052205460ff16156126fe576001600160a01b038082165f81815261013f6020908152604080832094881680845294909152808220805460ff19169055517fc8381dbc9d72f294db9b9a633c7497147bca68466d717a41aa1c9d4c4221f6409190a3612758565b6001600160a01b038082165f81815261013f6020908152604080832094881680845294909152808220805460ff19166001179055517f8f5b9ecbfffe5c27362de218379661bd1cb0afa18563c33122045df8613099ec9190a35b6001600160a01b038381165f9081526101406020526040902054818316911603610d8657610d868184612dfc565b5f80516020615f7383398151915261279d81612cb8565b6001600160a01b0382166127c457604051632fea089160e11b815260040160405180910390fd5b6127cf60cb8461382e565b6127ec5760405163ad2882d360e01b815260040160405180910390fd5b6001600160a01b038084165f81815260c9602052604080822080548786166001600160a01b0319821681179092559151919094169392849290917f1fad2e3fecc3cdff6159846b2a5d093b3bc70746158fcf6830313e74d852f2219190a450505050565b6002600154036128a25760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016110ec565b6002600155565b610131546001600160a01b0316158015906128e45750610131546128e1906201518090600160a01b90046001600160401b0316615cbd565b42115b15612ad7576040516370a0823160e01b81523060048201525f907f000000000000000000000000365accfca291e7d3914637abf1f7635db165bb096001600160a01b0316906370a0823190602401602060405180830381865afa15801561294d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906129719190615c0c565b610131546040516335313c2160e11b81526001600160a01b0391821660048201529192507f000000000000000000000000c8b194925d55d5de9555ad1db74c149329f71def1690636a627842906024015f604051808303815f87803b1580156129d8575f80fd5b505af11580156129ea573d5f803e3d5ffd5b50506040516370a0823160e01b81523060048201525f92508391506001600160a01b037f000000000000000000000000365accfca291e7d3914637abf1f7635db165bb0916906370a0823190602401602060405180830381865afa158015612a54573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612a789190615c0c565b612a829190615c60565b610131805467ffffffffffffffff60a01b1916600160a01b426001600160401b0316021790559050612ad47f000000000000000000000000365accfca291e7d3914637abf1f7635db165bb0982613998565b50505b6001600160a01b038082165f81815261014060205260409020549091169015612b90576001600160a01b037f000000000000000000000000d766f2b87de4b08c2239580366e49710180aba0281169063a972985e90831615612b395782612b3b565b835b6040516001600160e01b031960e084901b1681526001600160a01b0390911660048201526024015f604051808303815f87803b158015612b79575f80fd5b505af1158015612b8b573d5f803e3d5ffd5b505050505b612b9982614818565b6001600160a01b038216156103db5760408051606081018252610134546001600160701b0381168252600160701b81046001600160681b03166020830152600160d81b900464ffffffffff16918101919091525f612bf784836148b8565b90505f612c048484612fbb565b9050612c13858584848761312e565b5050505050565b6001600160a01b038083165f90815260fd6020526040902054168015801590612c4a57506001600160a01b038216155b15612c53578091505b6001600160a01b038216612c65578291505b5f612c6e610d8b565b90505f5b8151811015612c1357612c9f85838381518110612c9157612c91615bac565b602002602001015186613432565b5080612caa81615bd4565b915050612c72565b60018055565b610cfc8133614a4c565b5f80516020615f5383398151915282148015612d0557506001600160a01b0381165f9081526101356020526040902054600160701b90046001600160681b031615155b15612d235760405163433869fd60e11b815260040160405180910390fd5b6103db8282613b60565b5f610cec825490565b5f6115b08383614aa5565b5f805f80846060015164ffffffffff16421115612d9e57846040015164ffffffffff16856060015164ffffffffff161015612d7c575f612d90565b84604001518560600151612d909190615cd0565b64ffffffffff169150612dbf565b846040015164ffffffffff164203915042856060015164ffffffffff160390505b8185602001516001600160501b0316612dd89190615c73565b8186602001516001600160501b0316612df19190615c73565b935093505050915091565b612e05816128a9565b6001600160a01b038082165f9081526101356020908152604080832081516060808201845291546001600160701b0380821683526001600160681b03600160701b808404821685890190815264ffffffffff600160d81b958690048116878a01529a8d168a5261013d8952988790208751968701885254928316865282041695840186815291900490961692820192909252925190939091612ea8908390615cee565b6001600160681b039081169091526001600160a01b038681165f90815261013d6020908152604080832087518154898501518a8501516001600160701b039384166001600160d81b031990931692909217600160701b918a168202176001600160d81b0316600160d81b64ffffffffff938416810291909117909455968c168652610140855283862080546001600160a01b031916905583516060810185526101345492831681529682049097169386019390935290910490931692820192909252612f7b92508591908590859061312e565b6040515f906001600160a01b0386811691908616907f691c95c6dfadb8a9643f02b1ee3706982f7a9361ca534563e1f5944ae1471cac908490a450505050565b604080516060810182525f80825260208201819052918101919091526001600160a01b03831615610cec57506001600160a01b0382165f90815261013d60209081526040808320815160608101835290546001600160701b0381168252600160701b81046001600160681b031693820193909352600160d81b90920464ffffffffff169082018190529091036130595764ffffffffff421660408201525b5f61307c826040015164ffffffffff1662093a8062093a7f919091018190040290565b905061309c82602001516001600160681b0316835f0151855f015161373d565b6001600160681b0316602083015282516001600160701b031682524264ffffffffff8116604084015262093a8062093a7f909101819004025b80821015613126576020808401516001600160a01b0387165f90815261013e83526040808220868352909352919091206001600160681b03909116905561311f62093a8083615cbd565b91506130d5565b505092915050565b6001600160a01b0384166131475782915084935061320b565b6001600160a01b0384165f90815261013d6020908152604080832085518154938701519287015164ffffffffff16600160d81b026001600160d81b036001600160681b03909416600160701b026001600160d81b03199095166001600160701b039092169190911793909317919091169190911790556131d44262093a8062093a7f919091018190040290565b6020808501516001600160a01b0388165f90815261013e83526040808220948252939092529190206001600160681b039091169055505b5f61335883602001516001600160681b031685602001516001600160681b031684602001516001600160681b03167f000000000000000000000000ec6b8a3f3605b083f7044c0f31f2cac0caf1d4696001600160a01b03166370a082318a6040518263ffffffff1660e01b815260040161329491906001600160a01b0391909116815260200190565b602060405180830381865afa1580156132af573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906132d39190615c0c565b7f000000000000000000000000ec6b8a3f3605b083f7044c0f31f2cac0caf1d4696001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561332f573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133539190615c0c565b614acb565b6040805180820182526001600160401b039283168152610137545f1901831660208083019182526001600160a01b03909a165f90815261013c909a52919098209751885491518316600160401b026fffffffffffffffffffffffffffffffff19909216921691909117179095555050505050565b6133d68282611703565b156103db575f8281526097602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6001600160a01b038084165f90815260ff6020908152604080832093861683529281528282208351808501909452546001600160801b03808216808652600160801b9092041691840191909152909190801561354f57815160208301805161349b908390615d0e565b6001600160801b039081169091525f8085526001600160a01b03808a16825260ff60209081526040808420928b168085529282529092208651928701518416600160801b0292909316919091179091556134f791508583614b5a565b836001600160a01b0316856001600160a01b0316876001600160a01b03167fc1405953cccdad6b442e266c84d66ad671e2534c6584f8e6ef92802f7ad294d58460405161354691815260200190565b60405180910390a45b95945050505050565b6040516001600160a01b0380851660248301528316604482015260648101829052611d6a9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152614b8a565b610137546040808301515f1983015f908152610138602052919091205464ffffffffff918216600160d81b9091049091160361366c575f1981015f908152610138602090815260409182902084518154928601519386015164ffffffffff16600160d81b026001600160d81b036001600160681b03909516600160701b026001600160d81b03199094166001600160701b039092169190911792909217929092161790556136df565b5f818152610138602090815260409182902084518154928601519386015164ffffffffff16600160d81b026001600160d81b036001600160681b03909516600160701b026001600160d81b03199094166001600160701b0390921691909117929092179290921617905560018101610137555b5080516101348054602084015160409094015164ffffffffff16600160d81b026001600160d81b036001600160681b03909516600160701b026001600160d81b03199092166001600160701b03909416939093171792909216179055565b5f835f0361374c57505f6115b0565b61375f826001600160701b031660581c90565b62ffffff16613777846001600160701b031660581c90565b62ffffff16101561378957505f6115b0565b5f6137a3604085811c62ffffff9081169186901c16615d2e565b62ffffff169050805f036137da576001600160401b03848116906137c990851687615c73565b6137d39190615c9e565b915061380d565b8060010361380957633b9aca006001600160401b03858116906137ff90861688615c73565b6137c99190615c9e565b5f91505b61381b633b9aca0086615c9e565b821015613826575f91505b509392505050565b6001600160a01b0381165f90815260018301602052604081205415156115b0565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000093a8016158061388a575061388860cb612d2d565b155b1561389157565b5f61389a610d8b565b90505f5b81518110156103db575f8282815181106138ba576138ba615bac565b6020908102919091018101516001600160a01b0381165f90815260ca83526040808220815160808101835290546001600160601b03811682526001600160501b03600160601b8204169582019590955264ffffffffff600160b01b8604811692820192909252600160d81b9094041660608401529092509061393b90612d41565b506001600160a01b0383165f90815260ca60205260409020805464ffffffffff60b01b1916600160b01b4264ffffffffff160217905590508015613983576139838282613cf8565b5050808061399090615bd4565b91505061389e565b7f0000000000000000000000000000000000000000000000000000000000093a8064ffffffffff165f036139d0576103db8282613cf8565b6001600160a01b0382165f90815260ca6020908152604091829020825160808101845290546001600160601b03811682526001600160501b03600160601b8204169282019290925264ffffffffff600160b01b8304811693820193909352600160d81b9091048216606082015290613a6c9082907f0000000000000000000000000000000000000000000000000000000000093a801684614c5d565b6001600160a01b0383165f90815260ca602090815260409182902083518154928501519385015160609095015164ffffffffff908116600160d81b026001600160d81b0391909616600160b01b02166001600160b01b036001600160501b03909516600160601b026001600160b01b03199094166001600160601b03909216919091179290921792909216179190911790555050565b5f54610100900460ff16613b285760405162461bcd60e51b81526004016110ec90615d4a565b613b30614e1b565b565b5f54610100900460ff16613b585760405162461bcd60e51b81526004016110ec90615d4a565b613b30614e41565b613b6a8282611703565b6103db575f8281526097602090815260408083206001600160a01b03851684529091529020805460ff19166001179055613ba13390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b801580613c5d5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015613c37573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613c5b9190615c0c565b155b613cc85760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b60648201526084016110ec565b6040516001600160a01b038316602482015260448101829052610d8690849063095ea7b360e01b9060640161358c565b805f03613d03575050565b60408051606081018252610134546001600160701b038116808352600160701b82046001600160681b031660208401819052600160d81b90920464ffffffffff169290930191909152805f03613dad576001600160a01b0384165f90815260ca602052604081208054859290613d839084906001600160601b0316615d95565b92506101000a8154816001600160601b0302191690836001600160601b0316021790555050505050565b5f613dc1836001600160701b031660401c90565b6001600160a01b0386165f90815260fe6020908152604080832065ffffffffffff85168452825291829020825180840190935254600160401b90046001600160c01b0316908201526001600160401b034281168252919250908416908184613e31670de0b6b3a764000089615c73565b613e3b9190615c9e565b613e459190615db5565b81602001818151613e569190615de7565b6001600160c01b039081169091526001600160a01b039098165f90815260fe6020908152604080832065ffffffffffff909716835295815294902082519490920151909716600160401b026001600160401b03909316929092179091555050505050565b60408051606081018252610134546001600160701b0381168252600160701b81046001600160681b031660208301819052600160d81b90910464ffffffffff1692820192909252905f908310613f2557505f61013b8190556020820152670de0b6b3a7640000613fb9565b61013b545f90613f3d670de0b6b3a764000086615c73565b613f479190615c60565b905082602001516001600160681b031681613f629190615c9e565b613f6d906001615cbd565b91508083602001516001600160681b031683613f899190615c73565b613f939190615c60565b61013b55602083018051859190613fab908390615cee565b6001600160681b0316905250505b5f613fcc82670de0b6b3a7640000615c60565b8351909150613fe4906001600160701b031682614e67565b6001600160701b0316835264ffffffffff42166040840152611d6a836135c3565b6001600160a01b038281165f81815260ff602090815260408083209486168352938152838220845160808101865281546001600160801b03808216838901908152600160801b90920416606080840191909152908252865180880188526001909301546001600160401b0381168452600160401b90046001600160c01b03168385015281840192909252938352610135825284832085519182018652546001600160701b038116808352600160701b82046001600160681b0316938301849052600160d81b90910464ffffffffff1691909501529092908084036140f757505051516001600160801b03169050610cec565b5f61410b836001600160701b031660401c90565b6020858101518101516001600160a01b0389165f90815260fe8352604080822065ffffffffffff9590951680835294909352918220549293506001600160401b038616926141699190600160401b90046001600160c01b0316615e07565b6001600160a01b0389165f90815260fe602052604081206001600160c01b0392909216925090633b9aca0090826141a1876001615cbd565b815260208101919091526040015f20546141cb9190600160401b90046001600160c01b0316615c9e565b90506141df670de0b6b3a764000084615c73565b6141e98284615cbd565b6141f39087615c73565b6141fd9190615c9e565b87515161421391906001600160801b0316615cbd565b9a9950505050505050505050565b6001600160a01b0381165f90815261013560209081526040808320815160608101835290546001600160701b0381168252600160701b81046001600160681b0316938201849052600160d81b900464ffffffffff169181019190915290820361428c57505f92915050565b6001600160a01b0383165f90815261013c60209081526040918290208251808401845290546001600160401b038082168352600160401b9091041691810191909152908201514264ffffffffff909116036142f257516001600160401b03169392505050565b6001600160a01b038085165f908152610140602052604081205490911690811561431c578161431e565b855b6020840151845160408701519293506001600160401b039182169291169064ffffffffff1662093a8062093a7f8201819004025f5b6101008110156144bf5742821115614369574291505b82820384028a019950428203156144bf57604051627eeac760e11b81526001600160a01b038781166004830152602482018490525f917f000000000000000000000000d766f2b87de4b08c2239580366e49710180aba029091169062fdd58e90604401602060405180830381865afa1580156143e7573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061440b9190615c0c565b60405163bd85b03960e01b8152600481018590529091505f906001600160a01b037f000000000000000000000000d766f2b87de4b08c2239580366e49710180aba02169063bd85b03990602401602060405180830381865afa158015614473573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906144979190615c0c565b90506144a7898c84848b89614f1f565b975095509293505062093a8083019150600101614353565b50876040015164ffffffffff16420389816144dc576144dc615c8a565b049a9950505050505050505050565b5f6115b0836001600160a01b03841661502d565b5f6115b0836001600160a01b038416615117565b61451c836128a9565b6040805160608082018352610134546001600160701b0380821684526001600160681b03600160701b808404821660208088019190915264ffffffffff600160d81b958690048116888a01526001600160a01b038c165f90815261013583528981208a51808a018c52905496871681529386048516848401908152969095041682890152875195860188528386528501839052958401919091529051929392168511156145d45781602001516001600160681b031694505b845f036145f4576040516352c6c20960e11b815260040160405180910390fd5b602080840180516001600160681b0390889003811690915264ffffffffff421660408087019190915284830180518990039092169091526001600160a01b038089165f9081526101409093529120541680156146c5576001600160a01b0381165f90815261013d6020908152604091829020825160608101845290546001600160701b0381168252600160701b81046001600160681b0316928201838152600160d81b90910464ffffffffff169382019390935293508791906146b8908390615cee565b6001600160681b03169052505b6146ce846135c3565b6001600160a01b0387165f908152610135602090815260409182902085518154928701519387015164ffffffffff16600160d81b026001600160d81b036001600160681b03909516600160701b026001600160d81b03199094166001600160701b0390921691909117929092179290921617905561474f878285858861312e565b61013354614767906001600160a01b03168688614b5a565b846001600160a01b0316876001600160a01b03167f9b1bfa7fa9ee420a16e124f794c35ac9f90472acc99140eb2f6447c714cad8eb886040516147ac91815260200190565b60405180910390a3866001600160a01b03167f5fa7d0e13a31540b6d42936e522173de31fa0c53aa5aff71e63c60fe02b2b50e84602001515f6040516148079291906001600160681b03929092168252602082015260400190565b60405180910390a250505050505050565b61482061384f565b6001600160a01b03811615610cfc575f614838610d8b565b90505f5b815181101561487a576148688383838151811061485b5761485b615bac565b6020026020010151615163565b8061487281615bd4565b91505061483c565b50614883611995565b90505f5b8151811015610d86576148a68383838151811061485b5761485b615bac565b806148b081615bd4565b915050614887565b60408051606080820183525f80835260208084018290529284018190526001600160a01b0386168152610135835283812084519283018552546001600160701b038116808452600160701b82046001600160681b0316948401859052600160d81b90910464ffffffffff169483019490945284519193909261493c9290919061373d565b905081602001516001600160681b0316816001600160681b0316146149bb57836001600160a01b03167f5fa7d0e13a31540b6d42936e522173de31fa0c53aa5aff71e63c60fe02b2b50e828385602001516149979190615cee565b604080516001600160681b0393841681529290911660208301520160405180910390a25b6001600160681b03908116602080840191825293516001600160701b03908116845264ffffffffff42811660408087019182526001600160a01b039098165f908152610135909752969095208451815493519751909616600160d81b026001600160d81b0397909416600160701b026001600160d81b03199093169590911694909417179390931692909217905590565b614a568282611703565b6103db57614a63816153fd565b614a6e83602061540f565b604051602001614a7f929190615e49565b60408051601f198184030181529082905262461bcd60e51b82526110ec91600401615ebd565b5f825f018281548110614aba57614aba615bac565b905f5260205f200154905092915050565b5f845f03614ae2575067058d15e17628000061354f565b600a60048702048215614b1657600a8386860281614b0257614b02615c8a565b0460060281614b1357614b13615c8a565b04015b8686820281614b2757614b27615c8a565b04905085811115614b355750845b85670de0b6b3a7640000820281614b4e57614b4e615c8a565b04979650505050505050565b6040516001600160a01b038316602482015260448101829052610d8690849063a9059cbb60e01b9060640161358c565b5f614bde826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166155a49092919063ffffffff16565b905080515f1480614bfe575080806020019051810190614bfe9190615eef565b610d865760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016110ec565b8251614c72906001600160601b031682615cbd565b5f8452606084015190915064ffffffffff164210614cf657614c9c614c978383615c9e565b6155ba565b6001600160501b031660208401819052614cb7908390615c73565b614cc19082615c60565b6001600160601b031683524264ffffffffff81166040850152614ce5908390615cbd565b64ffffffffff166060840152505050565b5f82846060015164ffffffffff16614d0e9190615c60565b614d189042615c60565b90505f8185602001516001600160501b0316614d349190615c73565b9050614d4183600a615c73565b614d4c826009615c73565b11614e005784604001518560600151614d659190615cd0565b64ffffffffff1685602001516001600160501b0316614d849190615c73565b614d8e9084615cbd565b9250614d9d614c978585615c9e565b6001600160501b031660208601819052614db8908590615c73565b614dc29084615c60565b6001600160601b031685524264ffffffffff81166040870152614de6908590615cbd565b64ffffffffff908116606087015242166040860152612c13565b614e0983615625565b6001600160601b031685525050505050565b5f54610100900460ff16612cb25760405162461bcd60e51b81526004016110ec90615d4a565b5f54610100900460ff16613b305760405162461bcd60e51b81526004016110ec90615d4a565b5f80614e738460581c90565b90505f614e858560401c62ffffff1690565b90506001600160401b038581169085165f03614eaf5750506001015f670de0b6b3a7640000614f08565b633b9aca00670de0b6b3a76400006001600160401b0387168302041015614eef5760019190910190633b9aca006001600160401b03861690910204614f08565b670de0b6b3a76400006001600160401b03861682020490505b605883901b604083901b0181019695505050505050565b610137545f9081905f19015b80851015614f745760018186018101901c5f8181526101386020526040902054600160d81b900464ffffffffff168510614f6757809550614f6e565b6001810391505b50614f2b565b505f84815261013860209081526040808320815160608101835290546001600160701b038116808352600160701b82046001600160681b0390811684870152600160d81b90920464ffffffffff1693830193909352928b01518b51919493614fdf939116919061373d565b90505f6001600160a01b038b16614ff65781615000565b6150008b8761568c565b905061501c818385602001516001600160681b03168c8c614acb565b9b969a509598505050505050505050565b5f8181526001830160205260408120548015615107575f61504f600183615c60565b85549091505f9061506290600190615c60565b90508181146150c1575f865f01828154811061508057615080615bac565b905f5260205f200154905080875f0184815481106150a0576150a0615bac565b5f918252602080832090910192909255918252600188019052604090208390555b85548690806150d2576150d2615f0e565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f905560019350505050610cec565b5f915050610cec565b5092915050565b5f81815260018301602052604081205461515c57508154600181810184555f848152602080822090930184905584548482528286019093526040902091909155610cec565b505f610cec565b6001600160a01b038281165f90815260ff602090815260408083209385168352928152828220835160808101855281546001600160801b03808216838801908152600160801b9092041660608301528152845180860186526001909201546001600160401b03811683526001600160c01b03600160401b9091041682840152918201526101345490921c65ffffffffffff1690507f000000000000000000000000365accfca291e7d3914637abf1f7635db165bb096001600160a01b0316836001600160a01b03160361532e576001600160a01b038481165f9081526101406020908152604091829020548251606081018452610134546001600160701b0381168252600160701b81046001600160681b031693820193909352600160d81b90920464ffffffffff16928201929092526152a1929190911690612fbb565b508151515f906001600160801b03166152ba8686614005565b818103925014615328575f6152ce86614221565b845180516001600160801b03670de0b6b3a7640000868502049182011690915290915080831115615325576153257f000000000000000000000000365accfca291e7d3914637abf1f7635db165bb09828503613998565b50505b50615348565b6153388484614005565b82516001600160801b0390911690525b6001600160a01b039283165f81815260fe6020908152604080832065ffffffffffff90951683529381528382208451808601865290546001600160c01b03600160401b91829004811683850152878401838152426001600160401b0390811690945299909816845260ff83528584209484529382529390912093518051908201516001600160801b03908116600160801b02911617845594518051950151909316909202929091169190911760019190910155565b6060610cec6001600160a01b03831660145b60605f61541d836002615c73565b615428906002615cbd565b6001600160401b0381111561543f5761543f6159ec565b6040519080825280601f01601f191660200182016040528015615469576020820181803683370190505b509050600360fc1b815f8151811061548357615483615bac565b60200101906001600160f81b03191690815f1a905350600f60fb1b816001815181106154b1576154b1615bac565b60200101906001600160f81b03191690815f1a9053505f6154d3846002615c73565b6154de906001615cbd565b90505b6001811115615555576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061551257615512615bac565b1a60f81b82828151811061552857615528615bac565b60200101906001600160f81b03191690815f1a90535060049490941c9361554e81615f22565b90506154e1565b5083156115b05760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016110ec565b60606155b284845f8561572b565b949350505050565b5f6001600160501b038211156156215760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203860448201526530206269747360d01b60648201526084016110ec565b5090565b5f6001600160601b038211156156215760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201526536206269747360d01b60648201526084016110ec565b6001600160a01b0382165f90815261013d6020526040812054600160d81b900464ffffffffff165b808311156156fd576001600160a01b0384165f90815261013e6020908152604080832086845290915290205480156156ef579150610cec9050565b62093a8084039350506156b4565b5050506001600160a01b03165f90815261013d6020526040902054600160701b90046001600160681b031690565b60608247101561578c5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016110ec565b5f80866001600160a01b031685876040516157a79190615f37565b5f6040518083038185875af1925050503d805f81146157e1576040519150601f19603f3d011682016040523d82523d5f602084013e6157e6565b606091505b50915091506157f787838387615802565b979650505050505050565b606083156158705782515f03615869576001600160a01b0385163b6158695760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016110ec565b50816155b2565b6155b283838151156158855781518083602001fd5b8060405162461bcd60e51b81526004016110ec9190615ebd565b6001600160a01b0381168114610cfc575f80fd5b80356158be8161589f565b919050565b5f80604083850312156158d4575f80fd5b8235915060208301356158e68161589f565b809150509250929050565b5f60208284031215615901575f80fd5b81356001600160e01b0319811681146115b0575f80fd5b5f8060408385031215615929575f80fd5b82356159348161589f565b915060208301356158e68161589f565b5f8060408385031215615955575f80fd5b82356159608161589f565b946020939093013593505050565b5f6020828403121561597e575f80fd5b81356115b08161589f565b5f60208284031215615999575f80fd5b5035919050565b602080825282518282018190525f9190848201906040850190845b818110156159e05783516001600160a01b0316835292840192918401916001016159bb565b50909695505050505050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f830112615a0f575f80fd5b813560206001600160401b0380831115615a2b57615a2b6159ec565b8260051b604051601f19603f83011681018181108482111715615a5057615a506159ec565b604052938452858101830193838101925087851115615a6d575f80fd5b83870191505b848210156157f757615a84826158b3565b83529183019190830190615a73565b5f60208284031215615aa3575f80fd5b81356001600160401b03811115615ab8575f80fd5b6155b284828501615a00565b5f8060408385031215615ad5575f80fd5b8235615ae08161589f565b915060208301356001600160401b03811115615afa575f80fd5b615b0685828601615a00565b9150509250929050565b5f805f60608486031215615b22575f80fd5b8335615b2d8161589f565b92506020840135615b3d8161589f565b91506040840135615b4d8161589f565b809150509250925092565b5f8060408385031215615b69575f80fd5b50508035926020909101359150565b5f805f60608486031215615b8a575f80fd5b8335615b958161589f565b9250602084013591506040840135615b4d8161589f565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f60018201615be557615be5615bc0565b5060010190565b6001600160681b0381811683821601908082111561511057615110615bc0565b5f60208284031215615c1c575f80fd5b5051919050565b5f60208284031215615c33575f80fd5b81516115b08161589f565b5f8060408385031215615c4f575f80fd5b505080516020909101519092909150565b81810381811115610cec57610cec615bc0565b8082028115828204841417610cec57610cec615bc0565b634e487b7160e01b5f52601260045260245ffd5b5f82615cb857634e487b7160e01b5f52601260045260245ffd5b500490565b80820180821115610cec57610cec615bc0565b64ffffffffff82811682821603908082111561511057615110615bc0565b6001600160681b0382811682821603908082111561511057615110615bc0565b6001600160801b0381811683821601908082111561511057615110615bc0565b62ffffff82811682821603908082111561511057615110615bc0565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160601b0381811683821601908082111561511057615110615bc0565b6001600160c01b03828116828216818102831692918115828504821417615dde57615dde615bc0565b50505092915050565b6001600160c01b0381811683821601908082111561511057615110615bc0565b6001600160c01b0382811682821603908082111561511057615110615bc0565b5f5b83811015615e41578181015183820152602001615e29565b50505f910152565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f8351615e80816017850160208801615e27565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351615eb1816028840160208801615e27565b01602801949350505050565b602081525f8251806020840152615edb816040850160208701615e27565b601f01601f19169190910160400192915050565b5f60208284031215615eff575f80fd5b815180151581146115b0575f80fd5b634e487b7160e01b5f52603160045260245ffd5b5f81615f3057615f30615bc0565b505f190190565b5f8251615f48818460208701615e27565b919091019291505056fe8d4998b5742dab4ffcf0a281dc749862b71ae54ba53b035bfb1d3dbc23ddc35d0f51adb3f49e4a9bbb17b3783f025995eaf8c24be2c8eefff214bdfda05ef94da26469706673582212201d56ae33c2a8e80b2c0139a93f2ced33f4ee227a5a88aca8fe5aaa52d95155f564736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000365accfca291e7d3914637abf1f7635db165bb09000000000000000000000000ec6b8a3f3605b083f7044c0f31f2cac0caf1d469000000000000000000000000d766f2b87de4b08c2239580366e49710180aba02000000000000000000000000c8b194925d55d5de9555ad1db74c149329f71def
-----Decoded View---------------
Arg [0] : _fxn (address): 0x365AccFCa291e7D3914637ABf1F7635dB165Bb09
Arg [1] : _ve (address): 0xEC6B8A3F3605B083F7044C0F31f2cac0caf1d469
Arg [2] : _veHelper (address): 0xd766f2b87DE4b08c2239580366e49710180aba02
Arg [3] : _minter (address): 0xC8b194925D55d5dE9555AD1db74c149329F71DeF
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000365accfca291e7d3914637abf1f7635db165bb09
Arg [1] : 000000000000000000000000ec6b8a3f3605b083f7044c0f31f2cac0caf1d469
Arg [2] : 000000000000000000000000d766f2b87de4b08c2239580366e49710180aba02
Arg [3] : 000000000000000000000000c8b194925d55d5de9555ad1db74c149329f71def
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 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.