Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 211 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Mint FPI | 14792997 | 956 days ago | IN | 0 ETH | 0.0059268 | ||||
Mint FPI | 14776744 | 959 days ago | IN | 0 ETH | 0.00480098 | ||||
Redeem FPI | 14772052 | 960 days ago | IN | 0 ETH | 0.00449329 | ||||
Redeem FPI | 14765784 | 961 days ago | IN | 0 ETH | 0.01566541 | ||||
Mint FPI | 14764382 | 961 days ago | IN | 0 ETH | 0.01557971 | ||||
Redeem FPI | 14762220 | 961 days ago | IN | 0 ETH | 0.02494609 | ||||
Redeem FPI | 14759983 | 962 days ago | IN | 0 ETH | 0.05217787 | ||||
Redeem FPI | 14759779 | 962 days ago | IN | 0 ETH | 0.14625059 | ||||
Redeem FPI | 14759511 | 962 days ago | IN | 0 ETH | 0.05968037 | ||||
Redeem FPI | 14759496 | 962 days ago | IN | 0 ETH | 0.05361755 | ||||
Redeem FPI | 14759090 | 962 days ago | IN | 0 ETH | 0.04446588 | ||||
Redeem FPI | 14754189 | 963 days ago | IN | 0 ETH | 0.01073901 | ||||
Redeem FPI | 14753298 | 963 days ago | IN | 0 ETH | 0.00603666 | ||||
Mint FPI | 14750621 | 963 days ago | IN | 0 ETH | 0.00375462 | ||||
Redeem FPI | 14750274 | 963 days ago | IN | 0 ETH | 0.01003789 | ||||
Redeem FPI | 14747158 | 964 days ago | IN | 0 ETH | 0.00747473 | ||||
Redeem FPI | 14745435 | 964 days ago | IN | 0 ETH | 0.01746995 | ||||
Redeem FPI | 14744247 | 964 days ago | IN | 0 ETH | 0.01717913 | ||||
Redeem FPI | 14744229 | 964 days ago | IN | 0 ETH | 0.0314184 | ||||
Redeem FPI | 14744212 | 964 days ago | IN | 0 ETH | 0.02979931 | ||||
Redeem FPI | 14743664 | 964 days ago | IN | 0 ETH | 0.01453371 | ||||
Redeem FPI | 14743431 | 964 days ago | IN | 0 ETH | 0.01815065 | ||||
Mint FPI | 14743096 | 964 days ago | IN | 0 ETH | 0.01482202 | ||||
Redeem FPI | 14740793 | 965 days ago | IN | 0 ETH | 0.00312622 | ||||
Redeem FPI | 14737277 | 965 days ago | IN | 0 ETH | 0.01256113 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
FPIControllerPool
Compiler Version
v0.8.13+commit.abaa5c0e
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2022-04-05 */ // SPDX-License-Identifier: GPL-2.0-or-later pragma solidity >=0.8.0; // Sources flattened with hardhat v2.8.4 https://hardhat.org // File @openzeppelin/contracts/token/ERC20/[email protected] // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol) /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `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); /** * @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); } // File @openzeppelin/contracts/token/ERC20/extensions/[email protected] // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); } // File @openzeppelin/contracts/utils/[email protected] // OpenZeppelin Contracts v4.4.1 (utils/Context.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 Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } } // File @openzeppelin/contracts/token/ERC20/[email protected] // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol) /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom( address from, address to, uint256 amount ) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, _allowances[owner][spender] + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = _allowances[owner][spender]; require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `sender` to `recipient`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer( address from, address to, uint256 amount ) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; } _balances[to] += amount; emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; _balances[account] += amount; emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; } _totalSupply -= amount; emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Spend `amount` form the allowance of `owner` toward `spender`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance( address owner, address spender, uint256 amount ) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} } // File @openzeppelin/contracts/token/ERC20/extensions/[email protected] // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol) /** * @dev Extension of {ERC20} that allows token holders to destroy both their own * tokens and those that they have an allowance for, in a way that can be * recognized off-chain (via event analysis). */ abstract contract ERC20Burnable is Context, ERC20 { /** * @dev Destroys `amount` tokens from the caller. * * See {ERC20-_burn}. */ function burn(uint256 amount) public virtual { _burn(_msgSender(), amount); } /** * @dev Destroys `amount` tokens from `account`, deducting from the caller's * allowance. * * See {ERC20-_burn} and {ERC20-allowance}. * * Requirements: * * - the caller must have allowance for ``accounts``'s tokens of at least * `amount`. */ function burnFrom(address account, uint256 amount) public virtual { _spendAllowance(account, _msgSender(), amount); _burn(account, amount); } } // File @openzeppelin/contracts/security/[email protected] // OpenZeppelin Contracts v4.4.1 (security/Pausable.sol) /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); bool private _paused; /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { require(!paused(), "Pausable: paused"); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { require(paused(), "Pausable: not paused"); _; } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } } // File @openzeppelin/contracts/access/[email protected] // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { /** * @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; } // File @openzeppelin/contracts/utils/[email protected] // OpenZeppelin Contracts v4.4.1 (utils/Strings.sol) /** * @dev String operations. */ library Strings { bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef"; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @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] = _HEX_SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } } // File @openzeppelin/contracts/utils/introspection/[email protected] // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) /** * @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 IERC165 { /** * @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); } // File @openzeppelin/contracts/utils/introspection/[email protected] // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.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 ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } } // File @openzeppelin/contracts/access/[email protected] // OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControl.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: * * ``` * 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}: * * ``` * 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. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { 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, _msgSender()); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).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 `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 ", Strings.toHexString(uint160(account), 20), " is missing role ", Strings.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. */ 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. */ 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`. */ 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. * * [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. */ 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. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } } // File contracts/Staking/Owned.sol // https://docs.synthetix.io/contracts/Owned contract Owned { address public owner; address public nominatedOwner; constructor (address _owner) public { require(_owner != address(0), "Owner address cannot be 0"); owner = _owner; emit OwnerChanged(address(0), _owner); } function nominateNewOwner(address _owner) external onlyOwner { nominatedOwner = _owner; emit OwnerNominated(_owner); } function acceptOwnership() external { require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership"); emit OwnerChanged(owner, nominatedOwner); owner = nominatedOwner; nominatedOwner = address(0); } modifier onlyOwner { require(msg.sender == owner, "Only the contract owner may perform this action"); _; } event OwnerNominated(address newOwner); event OwnerChanged(address oldOwner, address newOwner); } // File contracts/ERC20/ERC20PermissionedMint.sol contract ERC20PermissionedMint is ERC20, ERC20Burnable, Owned { // Core address public timelock_address; // Minters address[] public minters_array; // Allowed to mint mapping(address => bool) public minters; // Mapping is also used for faster verification /* ========== CONSTRUCTOR ========== */ constructor( address _creator_address, address _timelock_address, string memory _name, string memory _symbol ) ERC20(_name, _symbol) Owned(_creator_address) { timelock_address = _timelock_address; } /* ========== MODIFIERS ========== */ modifier onlyByOwnGov() { require(msg.sender == timelock_address || msg.sender == owner, "Not owner or timelock"); _; } modifier onlyMinters() { require(minters[msg.sender] == true, "Only minters"); _; } /* ========== RESTRICTED FUNCTIONS ========== */ // Used by minters when user redeems function minter_burn_from(address b_address, uint256 b_amount) public onlyMinters { super.burnFrom(b_address, b_amount); emit TokenMinterBurned(b_address, msg.sender, b_amount); } // This function is what other minters will call to mint new tokens function minter_mint(address m_address, uint256 m_amount) public onlyMinters { super._mint(m_address, m_amount); emit TokenMinterMinted(msg.sender, m_address, m_amount); } // Adds whitelisted minters function addMinter(address minter_address) public onlyByOwnGov { require(minter_address != address(0), "Zero address detected"); require(minters[minter_address] == false, "Address already exists"); minters[minter_address] = true; minters_array.push(minter_address); emit MinterAdded(minter_address); } // Remove a minter function removeMinter(address minter_address) public onlyByOwnGov { require(minter_address != address(0), "Zero address detected"); require(minters[minter_address] == true, "Address nonexistant"); // Delete from the mapping delete minters[minter_address]; // 'Delete' from the array by setting the address to 0x0 for (uint i = 0; i < minters_array.length; i++){ if (minters_array[i] == minter_address) { minters_array[i] = address(0); // This will leave a null in the array and keep the indices the same break; } } emit MinterRemoved(minter_address); } /* ========== EVENTS ========== */ event TokenMinterBurned(address indexed from, address indexed to, uint256 amount); event TokenMinterMinted(address indexed from, address indexed to, uint256 amount); event MinterAdded(address minter_address); event MinterRemoved(address minter_address); } // File contracts/FPI/FPI.sol // ==================================================================== // | ______ _______ | // | / _____________ __ __ / ____(_____ ____ _____ ________ | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ | // | | // ==================================================================== // ================================ FPI =============================== // ==================================================================== // Frax Price Index // Initial peg target is the US CPI-U (Consumer Price Index, All Urban Consumers) // Frax Finance: https://github.com/FraxFinance // Primary Author(s) // Travis Moore: https://github.com/FortisFortuna // Jack Corddry: https://github.com/corddry // Reviewer(s) / Contributor(s) // Sam Kazemian: https://github.com/samkazemian // Rich Gee: https://github.com/zer0blockchain // Dennis: https://github.com/denett contract FPI is ERC20PermissionedMint { /* ========== CONSTRUCTOR ========== */ constructor( address _creator_address, address _timelock_address ) ERC20PermissionedMint(_creator_address, _timelock_address, "Frax Price Index", "FPI") { _mint(_creator_address, 100000000e18); // Genesis mint } } // File contracts/Frax/IFrax.sol interface IFrax { function COLLATERAL_RATIO_PAUSER() external view returns (bytes32); function DEFAULT_ADMIN_ADDRESS() external view returns (address); function DEFAULT_ADMIN_ROLE() external view returns (bytes32); function addPool(address pool_address ) external; function allowance(address owner, address spender ) external view returns (uint256); function approve(address spender, uint256 amount ) external returns (bool); function balanceOf(address account ) external view returns (uint256); function burn(uint256 amount ) external; function burnFrom(address account, uint256 amount ) external; function collateral_ratio_paused() external view returns (bool); function controller_address() external view returns (address); function creator_address() external view returns (address); function decimals() external view returns (uint8); function decreaseAllowance(address spender, uint256 subtractedValue ) external returns (bool); function eth_usd_consumer_address() external view returns (address); function eth_usd_price() external view returns (uint256); function frax_eth_oracle_address() external view returns (address); function frax_info() external view returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256); function frax_pools(address ) external view returns (bool); function frax_pools_array(uint256 ) external view returns (address); function frax_price() external view returns (uint256); function frax_step() external view returns (uint256); function fxs_address() external view returns (address); function fxs_eth_oracle_address() external view returns (address); function fxs_price() external view returns (uint256); function genesis_supply() external view returns (uint256); function getRoleAdmin(bytes32 role ) external view returns (bytes32); function getRoleMember(bytes32 role, uint256 index ) external view returns (address); function getRoleMemberCount(bytes32 role ) external view returns (uint256); function globalCollateralValue() external view returns (uint256); function global_collateral_ratio() external view returns (uint256); function grantRole(bytes32 role, address account ) external; function hasRole(bytes32 role, address account ) external view returns (bool); function increaseAllowance(address spender, uint256 addedValue ) external returns (bool); function last_call_time() external view returns (uint256); function minting_fee() external view returns (uint256); function name() external view returns (string memory); function owner_address() external view returns (address); function pool_burn_from(address b_address, uint256 b_amount ) external; function pool_mint(address m_address, uint256 m_amount ) external; function price_band() external view returns (uint256); function price_target() external view returns (uint256); function redemption_fee() external view returns (uint256); function refreshCollateralRatio() external; function refresh_cooldown() external view returns (uint256); function removePool(address pool_address ) external; function renounceRole(bytes32 role, address account ) external; function revokeRole(bytes32 role, address account ) external; function setController(address _controller_address ) external; function setETHUSDOracle(address _eth_usd_consumer_address ) external; function setFRAXEthOracle(address _frax_oracle_addr, address _weth_address ) external; function setFXSAddress(address _fxs_address ) external; function setFXSEthOracle(address _fxs_oracle_addr, address _weth_address ) external; function setFraxStep(uint256 _new_step ) external; function setMintingFee(uint256 min_fee ) external; function setOwner(address _owner_address ) external; function setPriceBand(uint256 _price_band ) external; function setPriceTarget(uint256 _new_price_target ) external; function setRedemptionFee(uint256 red_fee ) external; function setRefreshCooldown(uint256 _new_cooldown ) external; function setTimelock(address new_timelock ) external; function symbol() external view returns (string memory); function timelock_address() external view returns (address); function toggleCollateralRatio() external; function totalSupply() external view returns (uint256); function transfer(address recipient, uint256 amount ) external returns (bool); function transferFrom(address sender, address recipient, uint256 amount ) external returns (bool); function weth_address() external view returns (address); } // File contracts/Frax/IFraxAMOMinter.sol // MAY need to be updated interface IFraxAMOMinter { function FRAX() external view returns(address); function FXS() external view returns(address); function acceptOwnership() external; function addAMO(address amo_address, bool sync_too) external; function allAMOAddresses() external view returns(address[] memory); function allAMOsLength() external view returns(uint256); function amos(address) external view returns(bool); function amos_array(uint256) external view returns(address); function burnFraxFromAMO(uint256 frax_amount) external; function burnFxsFromAMO(uint256 fxs_amount) external; function col_idx() external view returns(uint256); function collatDollarBalance() external view returns(uint256); function collatDollarBalanceStored() external view returns(uint256); function collat_borrow_cap() external view returns(int256); function collat_borrowed_balances(address) external view returns(int256); function collat_borrowed_sum() external view returns(int256); function collateral_address() external view returns(address); function collateral_token() external view returns(address); function correction_offsets_amos(address, uint256) external view returns(int256); function custodian_address() external view returns(address); function dollarBalances() external view returns(uint256 frax_val_e18, uint256 collat_val_e18); // function execute(address _to, uint256 _value, bytes _data) external returns(bool, bytes); function fraxDollarBalanceStored() external view returns(uint256); function fraxTrackedAMO(address amo_address) external view returns(int256); function fraxTrackedGlobal() external view returns(int256); function frax_mint_balances(address) external view returns(int256); function frax_mint_cap() external view returns(int256); function frax_mint_sum() external view returns(int256); function fxs_mint_balances(address) external view returns(int256); function fxs_mint_cap() external view returns(int256); function fxs_mint_sum() external view returns(int256); function giveCollatToAMO(address destination_amo, uint256 collat_amount) external; function min_cr() external view returns(uint256); function mintFraxForAMO(address destination_amo, uint256 frax_amount) external; function mintFxsForAMO(address destination_amo, uint256 fxs_amount) external; function missing_decimals() external view returns(uint256); function nominateNewOwner(address _owner) external; function nominatedOwner() external view returns(address); function oldPoolCollectAndGive(address destination_amo) external; function oldPoolRedeem(uint256 frax_amount) external; function old_pool() external view returns(address); function owner() external view returns(address); function pool() external view returns(address); function receiveCollatFromAMO(uint256 usdc_amount) external; function recoverERC20(address tokenAddress, uint256 tokenAmount) external; function removeAMO(address amo_address, bool sync_too) external; function setAMOCorrectionOffsets(address amo_address, int256 frax_e18_correction, int256 collat_e18_correction) external; function setCollatBorrowCap(uint256 _collat_borrow_cap) external; function setCustodian(address _custodian_address) external; function setFraxMintCap(uint256 _frax_mint_cap) external; function setFraxPool(address _pool_address) external; function setFxsMintCap(uint256 _fxs_mint_cap) external; function setMinimumCollateralRatio(uint256 _min_cr) external; function setTimelock(address new_timelock) external; function syncDollarBalances() external; function timelock_address() external view returns(address); } // File contracts/Oracle/AggregatorV3Interface.sol interface AggregatorV3Interface { function decimals() external view returns (uint8); function description() external view returns (string memory); function version() external view returns (uint256); // getRoundData and latestRoundData should both raise "No data present" // if they do not have data to report, instead of returning unset values // which could be misinterpreted as actual reported values. function getRoundData(uint80 _roundId) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); } // File @chainlink/contracts/src/v0.8/vendor/[email protected] /** * @dev A library for working with mutable byte buffers in Solidity. * * Byte buffers are mutable and expandable, and provide a variety of primitives * for writing to them. At any time you can fetch a bytes object containing the * current contents of the buffer. The bytes object should not be stored between * operations, as it may change due to resizing of the buffer. */ library BufferChainlink { /** * @dev Represents a mutable buffer. Buffers have a current value (buf) and * a capacity. The capacity may be longer than the current value, in * which case it can be extended without the need to allocate more memory. */ struct buffer { bytes buf; uint256 capacity; } /** * @dev Initializes a buffer with an initial capacity. * @param buf The buffer to initialize. * @param capacity The number of bytes of space to allocate the buffer. * @return The buffer, for chaining. */ function init(buffer memory buf, uint256 capacity) internal pure returns (buffer memory) { if (capacity % 32 != 0) { capacity += 32 - (capacity % 32); } // Allocate space for the buffer data buf.capacity = capacity; assembly { let ptr := mload(0x40) mstore(buf, ptr) mstore(ptr, 0) mstore(0x40, add(32, add(ptr, capacity))) } return buf; } /** * @dev Initializes a new buffer from an existing bytes object. * Changes to the buffer may mutate the original value. * @param b The bytes object to initialize the buffer with. * @return A new buffer. */ function fromBytes(bytes memory b) internal pure returns (buffer memory) { buffer memory buf; buf.buf = b; buf.capacity = b.length; return buf; } function resize(buffer memory buf, uint256 capacity) private pure { bytes memory oldbuf = buf.buf; init(buf, capacity); append(buf, oldbuf); } function max(uint256 a, uint256 b) private pure returns (uint256) { if (a > b) { return a; } return b; } /** * @dev Sets buffer length to 0. * @param buf The buffer to truncate. * @return The original buffer, for chaining.. */ function truncate(buffer memory buf) internal pure returns (buffer memory) { assembly { let bufptr := mload(buf) mstore(bufptr, 0) } return buf; } /** * @dev Writes a byte string to a buffer. Resizes if doing so would exceed * the capacity of the buffer. * @param buf The buffer to append to. * @param off The start offset to write to. * @param data The data to append. * @param len The number of bytes to copy. * @return The original buffer, for chaining. */ function write( buffer memory buf, uint256 off, bytes memory data, uint256 len ) internal pure returns (buffer memory) { require(len <= data.length); if (off + len > buf.capacity) { resize(buf, max(buf.capacity, len + off) * 2); } uint256 dest; uint256 src; assembly { // Memory address of the buffer data let bufptr := mload(buf) // Length of existing buffer data let buflen := mload(bufptr) // Start address = buffer address + offset + sizeof(buffer length) dest := add(add(bufptr, 32), off) // Update buffer length if we're extending it if gt(add(len, off), buflen) { mstore(bufptr, add(len, off)) } src := add(data, 32) } // Copy word-length chunks while possible for (; len >= 32; len -= 32) { assembly { mstore(dest, mload(src)) } dest += 32; src += 32; } // Copy remaining bytes unchecked { uint256 mask = (256**(32 - len)) - 1; assembly { let srcpart := and(mload(src), not(mask)) let destpart := and(mload(dest), mask) mstore(dest, or(destpart, srcpart)) } } return buf; } /** * @dev Appends a byte string to a buffer. Resizes if doing so would exceed * the capacity of the buffer. * @param buf The buffer to append to. * @param data The data to append. * @param len The number of bytes to copy. * @return The original buffer, for chaining. */ function append( buffer memory buf, bytes memory data, uint256 len ) internal pure returns (buffer memory) { return write(buf, buf.buf.length, data, len); } /** * @dev Appends a byte string to a buffer. Resizes if doing so would exceed * the capacity of the buffer. * @param buf The buffer to append to. * @param data The data to append. * @return The original buffer, for chaining. */ function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) { return write(buf, buf.buf.length, data, data.length); } /** * @dev Writes a byte to the buffer. Resizes if doing so would exceed the * capacity of the buffer. * @param buf The buffer to append to. * @param off The offset to write the byte at. * @param data The data to append. * @return The original buffer, for chaining. */ function writeUint8( buffer memory buf, uint256 off, uint8 data ) internal pure returns (buffer memory) { if (off >= buf.capacity) { resize(buf, buf.capacity * 2); } assembly { // Memory address of the buffer data let bufptr := mload(buf) // Length of existing buffer data let buflen := mload(bufptr) // Address = buffer address + sizeof(buffer length) + off let dest := add(add(bufptr, off), 32) mstore8(dest, data) // Update buffer length if we extended it if eq(off, buflen) { mstore(bufptr, add(buflen, 1)) } } return buf; } /** * @dev Appends a byte to the buffer. Resizes if doing so would exceed the * capacity of the buffer. * @param buf The buffer to append to. * @param data The data to append. * @return The original buffer, for chaining. */ function appendUint8(buffer memory buf, uint8 data) internal pure returns (buffer memory) { return writeUint8(buf, buf.buf.length, data); } /** * @dev Writes up to 32 bytes to the buffer. Resizes if doing so would * exceed the capacity of the buffer. * @param buf The buffer to append to. * @param off The offset to write at. * @param data The data to append. * @param len The number of bytes to write (left-aligned). * @return The original buffer, for chaining. */ function write( buffer memory buf, uint256 off, bytes32 data, uint256 len ) private pure returns (buffer memory) { if (len + off > buf.capacity) { resize(buf, (len + off) * 2); } unchecked { uint256 mask = (256**len) - 1; // Right-align data data = data >> (8 * (32 - len)); assembly { // Memory address of the buffer data let bufptr := mload(buf) // Address = buffer address + sizeof(buffer length) + off + len let dest := add(add(bufptr, off), len) mstore(dest, or(and(mload(dest), not(mask)), data)) // Update buffer length if we extended it if gt(add(off, len), mload(bufptr)) { mstore(bufptr, add(off, len)) } } } return buf; } /** * @dev Writes a bytes20 to the buffer. Resizes if doing so would exceed the * capacity of the buffer. * @param buf The buffer to append to. * @param off The offset to write at. * @param data The data to append. * @return The original buffer, for chaining. */ function writeBytes20( buffer memory buf, uint256 off, bytes20 data ) internal pure returns (buffer memory) { return write(buf, off, bytes32(data), 20); } /** * @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed * the capacity of the buffer. * @param buf The buffer to append to. * @param data The data to append. * @return The original buffer, for chhaining. */ function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) { return write(buf, buf.buf.length, bytes32(data), 20); } /** * @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed * the capacity of the buffer. * @param buf The buffer to append to. * @param data The data to append. * @return The original buffer, for chaining. */ function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) { return write(buf, buf.buf.length, data, 32); } /** * @dev Writes an integer to the buffer. Resizes if doing so would exceed * the capacity of the buffer. * @param buf The buffer to append to. * @param off The offset to write at. * @param data The data to append. * @param len The number of bytes to write (right-aligned). * @return The original buffer, for chaining. */ function writeInt( buffer memory buf, uint256 off, uint256 data, uint256 len ) private pure returns (buffer memory) { if (len + off > buf.capacity) { resize(buf, (len + off) * 2); } uint256 mask = (256**len) - 1; assembly { // Memory address of the buffer data let bufptr := mload(buf) // Address = buffer address + off + sizeof(buffer length) + len let dest := add(add(bufptr, off), len) mstore(dest, or(and(mload(dest), not(mask)), data)) // Update buffer length if we extended it if gt(add(off, len), mload(bufptr)) { mstore(bufptr, add(off, len)) } } return buf; } /** * @dev Appends a byte to the end of the buffer. Resizes if doing so would * exceed the capacity of the buffer. * @param buf The buffer to append to. * @param data The data to append. * @return The original buffer. */ function appendInt( buffer memory buf, uint256 data, uint256 len ) internal pure returns (buffer memory) { return writeInt(buf, buf.buf.length, data, len); } } // File @chainlink/contracts/src/v0.8/vendor/[email protected] library CBORChainlink { using BufferChainlink for BufferChainlink.buffer; uint8 private constant MAJOR_TYPE_INT = 0; uint8 private constant MAJOR_TYPE_NEGATIVE_INT = 1; uint8 private constant MAJOR_TYPE_BYTES = 2; uint8 private constant MAJOR_TYPE_STRING = 3; uint8 private constant MAJOR_TYPE_ARRAY = 4; uint8 private constant MAJOR_TYPE_MAP = 5; uint8 private constant MAJOR_TYPE_TAG = 6; uint8 private constant MAJOR_TYPE_CONTENT_FREE = 7; uint8 private constant TAG_TYPE_BIGNUM = 2; uint8 private constant TAG_TYPE_NEGATIVE_BIGNUM = 3; function encodeFixedNumeric(BufferChainlink.buffer memory buf, uint8 major, uint64 value) private pure { if(value <= 23) { buf.appendUint8(uint8((major << 5) | value)); } else if (value <= 0xFF) { buf.appendUint8(uint8((major << 5) | 24)); buf.appendInt(value, 1); } else if (value <= 0xFFFF) { buf.appendUint8(uint8((major << 5) | 25)); buf.appendInt(value, 2); } else if (value <= 0xFFFFFFFF) { buf.appendUint8(uint8((major << 5) | 26)); buf.appendInt(value, 4); } else { buf.appendUint8(uint8((major << 5) | 27)); buf.appendInt(value, 8); } } function encodeIndefiniteLengthType(BufferChainlink.buffer memory buf, uint8 major) private pure { buf.appendUint8(uint8((major << 5) | 31)); } function encodeUInt(BufferChainlink.buffer memory buf, uint value) internal pure { if(value > 0xFFFFFFFFFFFFFFFF) { encodeBigNum(buf, value); } else { encodeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(value)); } } function encodeInt(BufferChainlink.buffer memory buf, int value) internal pure { if(value < -0x10000000000000000) { encodeSignedBigNum(buf, value); } else if(value > 0xFFFFFFFFFFFFFFFF) { encodeBigNum(buf, uint(value)); } else if(value >= 0) { encodeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(uint256(value))); } else { encodeFixedNumeric(buf, MAJOR_TYPE_NEGATIVE_INT, uint64(uint256(-1 - value))); } } function encodeBytes(BufferChainlink.buffer memory buf, bytes memory value) internal pure { encodeFixedNumeric(buf, MAJOR_TYPE_BYTES, uint64(value.length)); buf.append(value); } function encodeBigNum(BufferChainlink.buffer memory buf, uint value) internal pure { buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_BIGNUM)); encodeBytes(buf, abi.encode(value)); } function encodeSignedBigNum(BufferChainlink.buffer memory buf, int input) internal pure { buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_NEGATIVE_BIGNUM)); encodeBytes(buf, abi.encode(uint256(-1 - input))); } function encodeString(BufferChainlink.buffer memory buf, string memory value) internal pure { encodeFixedNumeric(buf, MAJOR_TYPE_STRING, uint64(bytes(value).length)); buf.append(bytes(value)); } function startArray(BufferChainlink.buffer memory buf) internal pure { encodeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY); } function startMap(BufferChainlink.buffer memory buf) internal pure { encodeIndefiniteLengthType(buf, MAJOR_TYPE_MAP); } function endSequence(BufferChainlink.buffer memory buf) internal pure { encodeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE); } } // File @chainlink/contracts/src/v0.8/[email protected] /** * @title Library for common Chainlink functions * @dev Uses imported CBOR library for encoding to buffer */ library Chainlink { uint256 internal constant defaultBufferSize = 256; // solhint-disable-line const-name-snakecase using CBORChainlink for BufferChainlink.buffer; struct Request { bytes32 id; address callbackAddress; bytes4 callbackFunctionId; uint256 nonce; BufferChainlink.buffer buf; } /** * @notice Initializes a Chainlink request * @dev Sets the ID, callback address, and callback function signature on the request * @param self The uninitialized request * @param jobId The Job Specification ID * @param callbackAddr The callback address * @param callbackFunc The callback function signature * @return The initialized request */ function initialize( Request memory self, bytes32 jobId, address callbackAddr, bytes4 callbackFunc ) internal pure returns (Chainlink.Request memory) { BufferChainlink.init(self.buf, defaultBufferSize); self.id = jobId; self.callbackAddress = callbackAddr; self.callbackFunctionId = callbackFunc; return self; } /** * @notice Sets the data for the buffer without encoding CBOR on-chain * @dev CBOR can be closed with curly-brackets {} or they can be left off * @param self The initialized request * @param data The CBOR data */ function setBuffer(Request memory self, bytes memory data) internal pure { BufferChainlink.init(self.buf, data.length); BufferChainlink.append(self.buf, data); } /** * @notice Adds a string value to the request with a given key name * @param self The initialized request * @param key The name of the key * @param value The string value to add */ function add( Request memory self, string memory key, string memory value ) internal pure { self.buf.encodeString(key); self.buf.encodeString(value); } /** * @notice Adds a bytes value to the request with a given key name * @param self The initialized request * @param key The name of the key * @param value The bytes value to add */ function addBytes( Request memory self, string memory key, bytes memory value ) internal pure { self.buf.encodeString(key); self.buf.encodeBytes(value); } /** * @notice Adds a int256 value to the request with a given key name * @param self The initialized request * @param key The name of the key * @param value The int256 value to add */ function addInt( Request memory self, string memory key, int256 value ) internal pure { self.buf.encodeString(key); self.buf.encodeInt(value); } /** * @notice Adds a uint256 value to the request with a given key name * @param self The initialized request * @param key The name of the key * @param value The uint256 value to add */ function addUint( Request memory self, string memory key, uint256 value ) internal pure { self.buf.encodeString(key); self.buf.encodeUInt(value); } /** * @notice Adds an array of strings to the request with a given key name * @param self The initialized request * @param key The name of the key * @param values The array of string values to add */ function addStringArray( Request memory self, string memory key, string[] memory values ) internal pure { self.buf.encodeString(key); self.buf.startArray(); for (uint256 i = 0; i < values.length; i++) { self.buf.encodeString(values[i]); } self.buf.endSequence(); } } // File @chainlink/contracts/src/v0.8/interfaces/[email protected] interface ENSInterface { // Logged when the owner of a node assigns a new owner to a subnode. event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner); // Logged when the owner of a node transfers ownership to a new account. event Transfer(bytes32 indexed node, address owner); // Logged when the resolver for a node changes. event NewResolver(bytes32 indexed node, address resolver); // Logged when the TTL of a node changes event NewTTL(bytes32 indexed node, uint64 ttl); function setSubnodeOwner( bytes32 node, bytes32 label, address owner ) external; function setResolver(bytes32 node, address resolver) external; function setOwner(bytes32 node, address owner) external; function setTTL(bytes32 node, uint64 ttl) external; function owner(bytes32 node) external view returns (address); function resolver(bytes32 node) external view returns (address); function ttl(bytes32 node) external view returns (uint64); } // File @chainlink/contracts/src/v0.8/interfaces/[email protected] interface LinkTokenInterface { function allowance(address owner, address spender) external view returns (uint256 remaining); function approve(address spender, uint256 value) external returns (bool success); function balanceOf(address owner) external view returns (uint256 balance); function decimals() external view returns (uint8 decimalPlaces); function decreaseApproval(address spender, uint256 addedValue) external returns (bool success); function increaseApproval(address spender, uint256 subtractedValue) external; function name() external view returns (string memory tokenName); function symbol() external view returns (string memory tokenSymbol); function totalSupply() external view returns (uint256 totalTokensIssued); function transfer(address to, uint256 value) external returns (bool success); function transferAndCall( address to, uint256 value, bytes calldata data ) external returns (bool success); function transferFrom( address from, address to, uint256 value ) external returns (bool success); } // File @chainlink/contracts/src/v0.8/interfaces/[email protected] interface ChainlinkRequestInterface { function oracleRequest( address sender, uint256 requestPrice, bytes32 serviceAgreementID, address callbackAddress, bytes4 callbackFunctionId, uint256 nonce, uint256 dataVersion, bytes calldata data ) external; function cancelOracleRequest( bytes32 requestId, uint256 payment, bytes4 callbackFunctionId, uint256 expiration ) external; } // File @chainlink/contracts/src/v0.8/interfaces/[email protected] interface OracleInterface { function fulfillOracleRequest( bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes32 data ) external returns (bool); function isAuthorizedSender(address node) external view returns (bool); function withdraw(address recipient, uint256 amount) external; function withdrawable() external view returns (uint256); } // File @chainlink/contracts/src/v0.8/interfaces/[email protected] interface OperatorInterface is OracleInterface, ChainlinkRequestInterface { function operatorRequest( address sender, uint256 payment, bytes32 specId, bytes4 callbackFunctionId, uint256 nonce, uint256 dataVersion, bytes calldata data ) external; function fulfillOracleRequest2( bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes calldata data ) external returns (bool); function ownerTransferAndCall( address to, uint256 value, bytes calldata data ) external returns (bool success); function distributeFunds(address payable[] calldata receivers, uint256[] calldata amounts) external payable; function getAuthorizedSenders() external returns (address[] memory); function setAuthorizedSenders(address[] calldata senders) external; function getForwarder() external returns (address); } // File @chainlink/contracts/src/v0.8/interfaces/[email protected] interface PointerInterface { function getAddress() external view returns (address); } // File @chainlink/contracts/src/v0.8/vendor/[email protected] abstract contract ENSResolver_Chainlink { function addr(bytes32 node) public view virtual returns (address); } // File @chainlink/contracts/src/v0.8/[email protected] /** * @title The ChainlinkClient contract * @notice Contract writers can inherit this contract in order to create requests for the * Chainlink network */ abstract contract ChainlinkClient { using Chainlink for Chainlink.Request; uint256 internal constant LINK_DIVISIBILITY = 10**18; uint256 private constant AMOUNT_OVERRIDE = 0; address private constant SENDER_OVERRIDE = address(0); uint256 private constant ORACLE_ARGS_VERSION = 1; uint256 private constant OPERATOR_ARGS_VERSION = 2; bytes32 private constant ENS_TOKEN_SUBNAME = keccak256("link"); bytes32 private constant ENS_ORACLE_SUBNAME = keccak256("oracle"); address private constant LINK_TOKEN_POINTER = 0xC89bD4E1632D3A43CB03AAAd5262cbe4038Bc571; ENSInterface private s_ens; bytes32 private s_ensNode; LinkTokenInterface private s_link; OperatorInterface private s_oracle; uint256 private s_requestCount = 1; mapping(bytes32 => address) private s_pendingRequests; event ChainlinkRequested(bytes32 indexed id); event ChainlinkFulfilled(bytes32 indexed id); event ChainlinkCancelled(bytes32 indexed id); /** * @notice Creates a request that can hold additional parameters * @param specId The Job Specification ID that the request will be created for * @param callbackAddr address to operate the callback on * @param callbackFunctionSignature function signature to use for the callback * @return A Chainlink Request struct in memory */ function buildChainlinkRequest( bytes32 specId, address callbackAddr, bytes4 callbackFunctionSignature ) internal pure returns (Chainlink.Request memory) { Chainlink.Request memory req; return req.initialize(specId, callbackAddr, callbackFunctionSignature); } /** * @notice Creates a request that can hold additional parameters * @param specId The Job Specification ID that the request will be created for * @param callbackFunctionSignature function signature to use for the callback * @return A Chainlink Request struct in memory */ function buildOperatorRequest(bytes32 specId, bytes4 callbackFunctionSignature) internal view returns (Chainlink.Request memory) { Chainlink.Request memory req; return req.initialize(specId, address(this), callbackFunctionSignature); } /** * @notice Creates a Chainlink request to the stored oracle address * @dev Calls `chainlinkRequestTo` with the stored oracle address * @param req The initialized Chainlink Request * @param payment The amount of LINK to send for the request * @return requestId The request ID */ function sendChainlinkRequest(Chainlink.Request memory req, uint256 payment) internal returns (bytes32) { return sendChainlinkRequestTo(address(s_oracle), req, payment); } /** * @notice Creates a Chainlink request to the specified oracle address * @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to * send LINK which creates a request on the target oracle contract. * Emits ChainlinkRequested event. * @param oracleAddress The address of the oracle for the request * @param req The initialized Chainlink Request * @param payment The amount of LINK to send for the request * @return requestId The request ID */ function sendChainlinkRequestTo( address oracleAddress, Chainlink.Request memory req, uint256 payment ) internal returns (bytes32 requestId) { uint256 nonce = s_requestCount; s_requestCount = nonce + 1; bytes memory encodedRequest = abi.encodeWithSelector( ChainlinkRequestInterface.oracleRequest.selector, SENDER_OVERRIDE, // Sender value - overridden by onTokenTransfer by the requesting contract's address AMOUNT_OVERRIDE, // Amount value - overridden by onTokenTransfer by the actual amount of LINK sent req.id, address(this), req.callbackFunctionId, nonce, ORACLE_ARGS_VERSION, req.buf.buf ); return _rawRequest(oracleAddress, nonce, payment, encodedRequest); } /** * @notice Creates a Chainlink request to the stored oracle address * @dev This function supports multi-word response * @dev Calls `sendOperatorRequestTo` with the stored oracle address * @param req The initialized Chainlink Request * @param payment The amount of LINK to send for the request * @return requestId The request ID */ function sendOperatorRequest(Chainlink.Request memory req, uint256 payment) internal returns (bytes32) { return sendOperatorRequestTo(address(s_oracle), req, payment); } /** * @notice Creates a Chainlink request to the specified oracle address * @dev This function supports multi-word response * @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to * send LINK which creates a request on the target oracle contract. * Emits ChainlinkRequested event. * @param oracleAddress The address of the oracle for the request * @param req The initialized Chainlink Request * @param payment The amount of LINK to send for the request * @return requestId The request ID */ function sendOperatorRequestTo( address oracleAddress, Chainlink.Request memory req, uint256 payment ) internal returns (bytes32 requestId) { uint256 nonce = s_requestCount; s_requestCount = nonce + 1; bytes memory encodedRequest = abi.encodeWithSelector( OperatorInterface.operatorRequest.selector, SENDER_OVERRIDE, // Sender value - overridden by onTokenTransfer by the requesting contract's address AMOUNT_OVERRIDE, // Amount value - overridden by onTokenTransfer by the actual amount of LINK sent req.id, req.callbackFunctionId, nonce, OPERATOR_ARGS_VERSION, req.buf.buf ); return _rawRequest(oracleAddress, nonce, payment, encodedRequest); } /** * @notice Make a request to an oracle * @param oracleAddress The address of the oracle for the request * @param nonce used to generate the request ID * @param payment The amount of LINK to send for the request * @param encodedRequest data encoded for request type specific format * @return requestId The request ID */ function _rawRequest( address oracleAddress, uint256 nonce, uint256 payment, bytes memory encodedRequest ) private returns (bytes32 requestId) { requestId = keccak256(abi.encodePacked(this, nonce)); s_pendingRequests[requestId] = oracleAddress; emit ChainlinkRequested(requestId); require(s_link.transferAndCall(oracleAddress, payment, encodedRequest), "unable to transferAndCall to oracle"); } /** * @notice Allows a request to be cancelled if it has not been fulfilled * @dev Requires keeping track of the expiration value emitted from the oracle contract. * Deletes the request from the `pendingRequests` mapping. * Emits ChainlinkCancelled event. * @param requestId The request ID * @param payment The amount of LINK sent for the request * @param callbackFunc The callback function specified for the request * @param expiration The time of the expiration for the request */ function cancelChainlinkRequest( bytes32 requestId, uint256 payment, bytes4 callbackFunc, uint256 expiration ) internal { OperatorInterface requested = OperatorInterface(s_pendingRequests[requestId]); delete s_pendingRequests[requestId]; emit ChainlinkCancelled(requestId); requested.cancelOracleRequest(requestId, payment, callbackFunc, expiration); } /** * @notice the next request count to be used in generating a nonce * @dev starts at 1 in order to ensure consistent gas cost * @return returns the next request count to be used in a nonce */ function getNextRequestCount() internal view returns (uint256) { return s_requestCount; } /** * @notice Sets the stored oracle address * @param oracleAddress The address of the oracle contract */ function setChainlinkOracle(address oracleAddress) internal { s_oracle = OperatorInterface(oracleAddress); } /** * @notice Sets the LINK token address * @param linkAddress The address of the LINK token contract */ function setChainlinkToken(address linkAddress) internal { s_link = LinkTokenInterface(linkAddress); } /** * @notice Sets the Chainlink token address for the public * network as given by the Pointer contract */ function setPublicChainlinkToken() internal { setChainlinkToken(PointerInterface(LINK_TOKEN_POINTER).getAddress()); } /** * @notice Retrieves the stored address of the LINK token * @return The address of the LINK token */ function chainlinkTokenAddress() internal view returns (address) { return address(s_link); } /** * @notice Retrieves the stored address of the oracle contract * @return The address of the oracle contract */ function chainlinkOracleAddress() internal view returns (address) { return address(s_oracle); } /** * @notice Allows for a request which was created on another contract to be fulfilled * on this contract * @param oracleAddress The address of the oracle contract that will fulfill the request * @param requestId The request ID used for the response */ function addChainlinkExternalRequest(address oracleAddress, bytes32 requestId) internal notPendingRequest(requestId) { s_pendingRequests[requestId] = oracleAddress; } /** * @notice Sets the stored oracle and LINK token contracts with the addresses resolved by ENS * @dev Accounts for subnodes having different resolvers * @param ensAddress The address of the ENS contract * @param node The ENS node hash */ function useChainlinkWithENS(address ensAddress, bytes32 node) internal { s_ens = ENSInterface(ensAddress); s_ensNode = node; bytes32 linkSubnode = keccak256(abi.encodePacked(s_ensNode, ENS_TOKEN_SUBNAME)); ENSResolver_Chainlink resolver = ENSResolver_Chainlink(s_ens.resolver(linkSubnode)); setChainlinkToken(resolver.addr(linkSubnode)); updateChainlinkOracleWithENS(); } /** * @notice Sets the stored oracle contract with the address resolved by ENS * @dev This may be called on its own as long as `useChainlinkWithENS` has been called previously */ function updateChainlinkOracleWithENS() internal { bytes32 oracleSubnode = keccak256(abi.encodePacked(s_ensNode, ENS_ORACLE_SUBNAME)); ENSResolver_Chainlink resolver = ENSResolver_Chainlink(s_ens.resolver(oracleSubnode)); setChainlinkOracle(resolver.addr(oracleSubnode)); } /** * @notice Ensures that the fulfillment is valid for this contract * @dev Use if the contract developer prefers methods instead of modifiers for validation * @param requestId The request ID for fulfillment */ function validateChainlinkCallback(bytes32 requestId) internal recordChainlinkFulfillment(requestId) // solhint-disable-next-line no-empty-blocks { } /** * @dev Reverts if the sender is not the oracle of the request. * Emits ChainlinkFulfilled event. * @param requestId The request ID for fulfillment */ modifier recordChainlinkFulfillment(bytes32 requestId) { require(msg.sender == s_pendingRequests[requestId], "Source must be the oracle of the request"); delete s_pendingRequests[requestId]; emit ChainlinkFulfilled(requestId); _; } /** * @dev Reverts if the request is already pending * @param requestId The request ID for fulfillment */ modifier notPendingRequest(bytes32 requestId) { require(s_pendingRequests[requestId] == address(0), "Request is already pending"); _; } } // File contracts/Math/BokkyPooBahsDateTimeLibrary.sol // ---------------------------------------------------------------------------- // BokkyPooBah's DateTime Library v1.01 // // A gas-efficient Solidity date and time library // // https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary // // Tested date range 1970/01/01 to 2345/12/31 // // Conventions: // Unit | Range | Notes // :-------- |:-------------:|:----- // timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC // year | 1970 ... 2345 | // month | 1 ... 12 | // day | 1 ... 31 | // hour | 0 ... 23 | // minute | 0 ... 59 | // second | 0 ... 59 | // dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday // // // Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018-2019. The MIT Licence. // ---------------------------------------------------------------------------- library BokkyPooBahsDateTimeLibrary { uint constant SECONDS_PER_DAY = 24 * 60 * 60; uint constant SECONDS_PER_HOUR = 60 * 60; uint constant SECONDS_PER_MINUTE = 60; int constant OFFSET19700101 = 2440588; uint constant DOW_MON = 1; uint constant DOW_TUE = 2; uint constant DOW_WED = 3; uint constant DOW_THU = 4; uint constant DOW_FRI = 5; uint constant DOW_SAT = 6; uint constant DOW_SUN = 7; // ------------------------------------------------------------------------ // Calculate the number of days from 1970/01/01 to year/month/day using // the date conversion algorithm from // http://aa.usno.navy.mil/faq/docs/JD_Formula.php // and subtracting the offset 2440588 so that 1970/01/01 is day 0 // // days = day // - 32075 // + 1461 * (year + 4800 + (month - 14) / 12) / 4 // + 367 * (month - 2 - (month - 14) / 12 * 12) / 12 // - 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4 // - offset // ------------------------------------------------------------------------ function _daysFromDate(uint year, uint month, uint day) internal pure returns (uint _days) { require(year >= 1970); int _year = int(year); int _month = int(month); int _day = int(day); int __days = _day - 32075 + 1461 * (_year + 4800 + (_month - 14) / 12) / 4 + 367 * (_month - 2 - (_month - 14) / 12 * 12) / 12 - 3 * ((_year + 4900 + (_month - 14) / 12) / 100) / 4 - OFFSET19700101; _days = uint(__days); } // ------------------------------------------------------------------------ // Calculate year/month/day from the number of days since 1970/01/01 using // the date conversion algorithm from // http://aa.usno.navy.mil/faq/docs/JD_Formula.php // and adding the offset 2440588 so that 1970/01/01 is day 0 // // int L = days + 68569 + offset // int N = 4 * L / 146097 // L = L - (146097 * N + 3) / 4 // year = 4000 * (L + 1) / 1461001 // L = L - 1461 * year / 4 + 31 // month = 80 * L / 2447 // dd = L - 2447 * month / 80 // L = month / 11 // month = month + 2 - 12 * L // year = 100 * (N - 49) + year + L // ------------------------------------------------------------------------ function _daysToDate(uint _days) internal pure returns (uint year, uint month, uint day) { int __days = int(_days); int L = __days + 68569 + OFFSET19700101; int N = 4 * L / 146097; L = L - (146097 * N + 3) / 4; int _year = 4000 * (L + 1) / 1461001; L = L - 1461 * _year / 4 + 31; int _month = 80 * L / 2447; int _day = L - 2447 * _month / 80; L = _month / 11; _month = _month + 2 - 12 * L; _year = 100 * (N - 49) + _year + L; year = uint(_year); month = uint(_month); day = uint(_day); } function timestampFromDate(uint year, uint month, uint day) internal pure returns (uint timestamp) { timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY; } function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (uint timestamp) { timestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + hour * SECONDS_PER_HOUR + minute * SECONDS_PER_MINUTE + second; } function timestampToDate(uint timestamp) internal pure returns (uint year, uint month, uint day) { (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); } function timestampToDateTime(uint timestamp) internal pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { (year, month, day) = _daysToDate(timestamp / SECONDS_PER_DAY); uint secs = timestamp % SECONDS_PER_DAY; hour = secs / SECONDS_PER_HOUR; secs = secs % SECONDS_PER_HOUR; minute = secs / SECONDS_PER_MINUTE; second = secs % SECONDS_PER_MINUTE; } function isValidDate(uint year, uint month, uint day) internal pure returns (bool valid) { if (year >= 1970 && month > 0 && month <= 12) { uint daysInMonth = _getDaysInMonth(year, month); if (day > 0 && day <= daysInMonth) { valid = true; } } } function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) internal pure returns (bool valid) { if (isValidDate(year, month, day)) { if (hour < 24 && minute < 60 && second < 60) { valid = true; } } } function isLeapYear(uint timestamp) internal pure returns (bool leapYear) { (uint year,,) = _daysToDate(timestamp / SECONDS_PER_DAY); leapYear = _isLeapYear(year); } function _isLeapYear(uint year) internal pure returns (bool leapYear) { leapYear = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); } function isWeekDay(uint timestamp) internal pure returns (bool weekDay) { weekDay = getDayOfWeek(timestamp) <= DOW_FRI; } function isWeekEnd(uint timestamp) internal pure returns (bool weekEnd) { weekEnd = getDayOfWeek(timestamp) >= DOW_SAT; } function getDaysInMonth(uint timestamp) internal pure returns (uint daysInMonth) { (uint year, uint month,) = _daysToDate(timestamp / SECONDS_PER_DAY); daysInMonth = _getDaysInMonth(year, month); } function _getDaysInMonth(uint year, uint month) internal pure returns (uint daysInMonth) { if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { daysInMonth = 31; } else if (month != 2) { daysInMonth = 30; } else { daysInMonth = _isLeapYear(year) ? 29 : 28; } } // 1 = Monday, 7 = Sunday function getDayOfWeek(uint timestamp) internal pure returns (uint dayOfWeek) { uint _days = timestamp / SECONDS_PER_DAY; dayOfWeek = (_days + 3) % 7 + 1; } function getYear(uint timestamp) internal pure returns (uint year) { (year,,) = _daysToDate(timestamp / SECONDS_PER_DAY); } function getMonth(uint timestamp) internal pure returns (uint month) { (,month,) = _daysToDate(timestamp / SECONDS_PER_DAY); } function getDay(uint timestamp) internal pure returns (uint day) { (,,day) = _daysToDate(timestamp / SECONDS_PER_DAY); } function getHour(uint timestamp) internal pure returns (uint hour) { uint secs = timestamp % SECONDS_PER_DAY; hour = secs / SECONDS_PER_HOUR; } function getMinute(uint timestamp) internal pure returns (uint minute) { uint secs = timestamp % SECONDS_PER_HOUR; minute = secs / SECONDS_PER_MINUTE; } function getSecond(uint timestamp) internal pure returns (uint second) { second = timestamp % SECONDS_PER_MINUTE; } function addYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); year += _years; uint daysInMonth = _getDaysInMonth(year, month); if (day > daysInMonth) { day = daysInMonth; } newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; require(newTimestamp >= timestamp); } function addMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); month += _months; year += (month - 1) / 12; month = (month - 1) % 12 + 1; uint daysInMonth = _getDaysInMonth(year, month); if (day > daysInMonth) { day = daysInMonth; } newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; require(newTimestamp >= timestamp); } function addDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { newTimestamp = timestamp + _days * SECONDS_PER_DAY; require(newTimestamp >= timestamp); } function addHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { newTimestamp = timestamp + _hours * SECONDS_PER_HOUR; require(newTimestamp >= timestamp); } function addMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { newTimestamp = timestamp + _minutes * SECONDS_PER_MINUTE; require(newTimestamp >= timestamp); } function addSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { newTimestamp = timestamp + _seconds; require(newTimestamp >= timestamp); } function subYears(uint timestamp, uint _years) internal pure returns (uint newTimestamp) { (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); year -= _years; uint daysInMonth = _getDaysInMonth(year, month); if (day > daysInMonth) { day = daysInMonth; } newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; require(newTimestamp <= timestamp); } function subMonths(uint timestamp, uint _months) internal pure returns (uint newTimestamp) { (uint year, uint month, uint day) = _daysToDate(timestamp / SECONDS_PER_DAY); uint yearMonth = year * 12 + (month - 1) - _months; year = yearMonth / 12; month = yearMonth % 12 + 1; uint daysInMonth = _getDaysInMonth(year, month); if (day > daysInMonth) { day = daysInMonth; } newTimestamp = _daysFromDate(year, month, day) * SECONDS_PER_DAY + timestamp % SECONDS_PER_DAY; require(newTimestamp <= timestamp); } function subDays(uint timestamp, uint _days) internal pure returns (uint newTimestamp) { newTimestamp = timestamp - _days * SECONDS_PER_DAY; require(newTimestamp <= timestamp); } function subHours(uint timestamp, uint _hours) internal pure returns (uint newTimestamp) { newTimestamp = timestamp - _hours * SECONDS_PER_HOUR; require(newTimestamp <= timestamp); } function subMinutes(uint timestamp, uint _minutes) internal pure returns (uint newTimestamp) { newTimestamp = timestamp - _minutes * SECONDS_PER_MINUTE; require(newTimestamp <= timestamp); } function subSeconds(uint timestamp, uint _seconds) internal pure returns (uint newTimestamp) { newTimestamp = timestamp - _seconds; require(newTimestamp <= timestamp); } function diffYears(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _years) { require(fromTimestamp <= toTimestamp); (uint fromYear,,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); (uint toYear,,) = _daysToDate(toTimestamp / SECONDS_PER_DAY); _years = toYear - fromYear; } function diffMonths(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _months) { require(fromTimestamp <= toTimestamp); (uint fromYear, uint fromMonth,) = _daysToDate(fromTimestamp / SECONDS_PER_DAY); (uint toYear, uint toMonth,) = _daysToDate(toTimestamp / SECONDS_PER_DAY); _months = toYear * 12 + toMonth - fromYear * 12 - fromMonth; } function diffDays(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _days) { require(fromTimestamp <= toTimestamp); _days = (toTimestamp - fromTimestamp) / SECONDS_PER_DAY; } function diffHours(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _hours) { require(fromTimestamp <= toTimestamp); _hours = (toTimestamp - fromTimestamp) / SECONDS_PER_HOUR; } function diffMinutes(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _minutes) { require(fromTimestamp <= toTimestamp); _minutes = (toTimestamp - fromTimestamp) / SECONDS_PER_MINUTE; } function diffSeconds(uint fromTimestamp, uint toTimestamp) internal pure returns (uint _seconds) { require(fromTimestamp <= toTimestamp); _seconds = toTimestamp - fromTimestamp; } } // File contracts/Math/BokkyPooBahsDateTimeContract.sol // ---------------------------------------------------------------------------- // BokkyPooBah's DateTime Library v1.00 - Contract Instance // // A gas-efficient Solidity date and time library // // https://github.com/bokkypoobah/BokkyPooBahsDateTimeLibrary // // Tested date range 1970/01/01 to 2345/12/31 // // Conventions: // Unit | Range | Notes // :-------- |:-------------:|:----- // timestamp | >= 0 | Unix timestamp, number of seconds since 1970/01/01 00:00:00 UTC // year | 1970 ... 2345 | // month | 1 ... 12 | // day | 1 ... 31 | // hour | 0 ... 23 | // minute | 0 ... 59 | // second | 0 ... 59 | // dayOfWeek | 1 ... 7 | 1 = Monday, ..., 7 = Sunday // // // Enjoy. (c) BokkyPooBah / Bok Consulting Pty Ltd 2018. // // GNU Lesser General Public License 3.0 // https://www.gnu.org/licenses/lgpl-3.0.en.html // ---------------------------------------------------------------------------- contract BokkyPooBahsDateTimeContract { uint public constant SECONDS_PER_DAY = 24 * 60 * 60; uint public constant SECONDS_PER_HOUR = 60 * 60; uint public constant SECONDS_PER_MINUTE = 60; int public constant OFFSET19700101 = 2440588; uint public constant DOW_MON = 1; uint public constant DOW_TUE = 2; uint public constant DOW_WED = 3; uint public constant DOW_THU = 4; uint public constant DOW_FRI = 5; uint public constant DOW_SAT = 6; uint public constant DOW_SUN = 7; function _now() public view returns (uint timestamp) { timestamp = block.timestamp; } function _nowDateTime() public view returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { (year, month, day, hour, minute, second) = BokkyPooBahsDateTimeLibrary.timestampToDateTime(block.timestamp); } function _daysFromDate(uint year, uint month, uint day) public pure returns (uint _days) { return BokkyPooBahsDateTimeLibrary._daysFromDate(year, month, day); } function _daysToDate(uint _days) public pure returns (uint year, uint month, uint day) { return BokkyPooBahsDateTimeLibrary._daysToDate(_days); } function timestampFromDate(uint year, uint month, uint day) public pure returns (uint timestamp) { return BokkyPooBahsDateTimeLibrary.timestampFromDate(year, month, day); } function timestampFromDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (uint timestamp) { return BokkyPooBahsDateTimeLibrary.timestampFromDateTime(year, month, day, hour, minute, second); } function timestampToDate(uint timestamp) public pure returns (uint year, uint month, uint day) { (year, month, day) = BokkyPooBahsDateTimeLibrary.timestampToDate(timestamp); } function timestampToDateTime(uint timestamp) public pure returns (uint year, uint month, uint day, uint hour, uint minute, uint second) { (year, month, day, hour, minute, second) = BokkyPooBahsDateTimeLibrary.timestampToDateTime(timestamp); } function isValidDate(uint year, uint month, uint day) public pure returns (bool valid) { valid = BokkyPooBahsDateTimeLibrary.isValidDate(year, month, day); } function isValidDateTime(uint year, uint month, uint day, uint hour, uint minute, uint second) public pure returns (bool valid) { valid = BokkyPooBahsDateTimeLibrary.isValidDateTime(year, month, day, hour, minute, second); } function isLeapYear(uint timestamp) public pure returns (bool leapYear) { leapYear = BokkyPooBahsDateTimeLibrary.isLeapYear(timestamp); } function _isLeapYear(uint year) public pure returns (bool leapYear) { leapYear = BokkyPooBahsDateTimeLibrary._isLeapYear(year); } function isWeekDay(uint timestamp) public pure returns (bool weekDay) { weekDay = BokkyPooBahsDateTimeLibrary.isWeekDay(timestamp); } function isWeekEnd(uint timestamp) public pure returns (bool weekEnd) { weekEnd = BokkyPooBahsDateTimeLibrary.isWeekEnd(timestamp); } function getDaysInMonth(uint timestamp) public pure returns (uint daysInMonth) { daysInMonth = BokkyPooBahsDateTimeLibrary.getDaysInMonth(timestamp); } function _getDaysInMonth(uint year, uint month) public pure returns (uint daysInMonth) { daysInMonth = BokkyPooBahsDateTimeLibrary._getDaysInMonth(year, month); } function getDayOfWeek(uint timestamp) public pure returns (uint dayOfWeek) { dayOfWeek = BokkyPooBahsDateTimeLibrary.getDayOfWeek(timestamp); } function getYear(uint timestamp) public pure returns (uint year) { year = BokkyPooBahsDateTimeLibrary.getYear(timestamp); } function getMonth(uint timestamp) public pure returns (uint month) { month = BokkyPooBahsDateTimeLibrary.getMonth(timestamp); } function getDay(uint timestamp) public pure returns (uint day) { day = BokkyPooBahsDateTimeLibrary.getDay(timestamp); } function getHour(uint timestamp) public pure returns (uint hour) { hour = BokkyPooBahsDateTimeLibrary.getHour(timestamp); } function getMinute(uint timestamp) public pure returns (uint minute) { minute = BokkyPooBahsDateTimeLibrary.getMinute(timestamp); } function getSecond(uint timestamp) public pure returns (uint second) { second = BokkyPooBahsDateTimeLibrary.getSecond(timestamp); } function addYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { newTimestamp = BokkyPooBahsDateTimeLibrary.addYears(timestamp, _years); } function addMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { newTimestamp = BokkyPooBahsDateTimeLibrary.addMonths(timestamp, _months); } function addDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { newTimestamp = BokkyPooBahsDateTimeLibrary.addDays(timestamp, _days); } function addHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { newTimestamp = BokkyPooBahsDateTimeLibrary.addHours(timestamp, _hours); } function addMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { newTimestamp = BokkyPooBahsDateTimeLibrary.addMinutes(timestamp, _minutes); } function addSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { newTimestamp = BokkyPooBahsDateTimeLibrary.addSeconds(timestamp, _seconds); } function subYears(uint timestamp, uint _years) public pure returns (uint newTimestamp) { newTimestamp = BokkyPooBahsDateTimeLibrary.subYears(timestamp, _years); } function subMonths(uint timestamp, uint _months) public pure returns (uint newTimestamp) { newTimestamp = BokkyPooBahsDateTimeLibrary.subMonths(timestamp, _months); } function subDays(uint timestamp, uint _days) public pure returns (uint newTimestamp) { newTimestamp = BokkyPooBahsDateTimeLibrary.subDays(timestamp, _days); } function subHours(uint timestamp, uint _hours) public pure returns (uint newTimestamp) { newTimestamp = BokkyPooBahsDateTimeLibrary.subHours(timestamp, _hours); } function subMinutes(uint timestamp, uint _minutes) public pure returns (uint newTimestamp) { newTimestamp = BokkyPooBahsDateTimeLibrary.subMinutes(timestamp, _minutes); } function subSeconds(uint timestamp, uint _seconds) public pure returns (uint newTimestamp) { newTimestamp = BokkyPooBahsDateTimeLibrary.subSeconds(timestamp, _seconds); } function diffYears(uint fromTimestamp, uint toTimestamp) public pure returns (uint _years) { _years = BokkyPooBahsDateTimeLibrary.diffYears(fromTimestamp, toTimestamp); } function diffMonths(uint fromTimestamp, uint toTimestamp) public pure returns (uint _months) { _months = BokkyPooBahsDateTimeLibrary.diffMonths(fromTimestamp, toTimestamp); } function diffDays(uint fromTimestamp, uint toTimestamp) public pure returns (uint _days) { _days = BokkyPooBahsDateTimeLibrary.diffDays(fromTimestamp, toTimestamp); } function diffHours(uint fromTimestamp, uint toTimestamp) public pure returns (uint _hours) { _hours = BokkyPooBahsDateTimeLibrary.diffHours(fromTimestamp, toTimestamp); } function diffMinutes(uint fromTimestamp, uint toTimestamp) public pure returns (uint _minutes) { _minutes = BokkyPooBahsDateTimeLibrary.diffMinutes(fromTimestamp, toTimestamp); } function diffSeconds(uint fromTimestamp, uint toTimestamp) public pure returns (uint _seconds) { _seconds = BokkyPooBahsDateTimeLibrary.diffSeconds(fromTimestamp, toTimestamp); } } // File contracts/Uniswap/TransferHelper.sol // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false library TransferHelper { function safeApprove(address token, address to, uint value) internal { // bytes4(keccak256(bytes('approve(address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: APPROVE_FAILED'); } function safeTransfer(address token, address to, uint value) internal { // bytes4(keccak256(bytes('transfer(address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FAILED'); } function safeTransferFrom(address token, address from, address to, uint value) internal { // bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper: TRANSFER_FROM_FAILED'); } function safeTransferETH(address to, uint value) internal { (bool success,) = to.call{value:value}(new bytes(0)); require(success, 'TransferHelper: ETH_TRANSFER_FAILED'); } } // File contracts/Oracle/CPITrackerOracle.sol // ==================================================================== // | ______ _______ | // | / _____________ __ __ / ____(_____ ____ _____ ________ | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ | // | | // ==================================================================== // ========================= CPITrackerOracle ========================= // ==================================================================== // Pull in CPI data and track it in Dec 2021 dollars // Frax Finance: https://github.com/FraxFinance // Primary Author(s) // Travis Moore: https://github.com/FortisFortuna // Reviewer(s) / Contributor(s) // Sam Kazemian: https://github.com/samkazemian // Rich Gee: https://github.com/zer0blockchain // Dennis: https://github.com/denett // References // https://docs.chain.link/docs/make-a-http-get-request/#api-consumer-example contract CPITrackerOracle is Owned, ChainlinkClient { using Chainlink for Chainlink.Request; // Core BokkyPooBahsDateTimeContract public time_contract; address public timelock_address; address public bot_address; // Data uint256 public cpi_last = 28012600000; // Dec 2021 CPI-U, 280.126 * 100000000 uint256 public cpi_target = 28193300000; // Jan 2022 CPI-U, 281.933 * 100000000 uint256 public peg_price_last = 1e18; // Use currPegPrice(). Will always be in Dec 2021 dollars uint256 public peg_price_target = 1006450668627688968; // Will always be in Dec 2021 dollars // Chainlink address public oracle; // Chainlink CPI oracle address bytes32 public jobId; // Job ID for the CPI-U date uint256 public fee; // LINK token fee // Tracking uint256 public stored_year = 2022; // Last time (year) the stored CPI data was updated uint256 public stored_month = 1; // Last time (month) the stored CPI data was updated uint256 public lastUpdateTime = 1644886800; // Last time the stored CPI data was updated. uint256 public ramp_period = 28 * 86400; // Apply the CPI delta to the peg price over a set period uint256 public future_ramp_period = 28 * 86400; CPIObservation[] public cpi_observations; // Historical tracking of CPI data // Safety uint256 public max_delta_frac = 25000; // 2.5%. Max month-to-month CPI delta. // Misc string[13] public month_names; // English names of the 12 months uint256 public fulfill_ready_day = 15; // Date of the month that CPI data is expected to by ready by /* ========== STRUCTS ========== */ struct CPIObservation { uint256 result_year; uint256 result_month; uint256 cpi_target; uint256 peg_price_target; uint256 timestamp; } /* ========== MODIFIERS ========== */ modifier onlyByOwnGov() { require(msg.sender == owner || msg.sender == timelock_address, "Not owner or timelock"); _; } modifier onlyByOwnGovBot() { require(msg.sender == owner || msg.sender == timelock_address || msg.sender == bot_address, "Not owner, tlck, or bot"); _; } /* ========== CONSTRUCTOR ========== */ constructor ( address _creator_address, address _timelock_address ) Owned(_creator_address) { timelock_address = _timelock_address; // Initialize the array. Cannot be done in the declaration month_names = [ '', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ]; // CPI [Ethereum] // ================================= // setPublicChainlinkToken(); // time_contract = BokkyPooBahsDateTimeContract(0x90503D86E120B3B309CEBf00C2CA013aB3624736); // oracle = 0x049Bd8C3adC3fE7d3Fc2a44541d955A537c2A484; // jobId = "1c309d42c7084b34b1acf1a89e7b51fc"; // fee = 50e18; // 50 LINK // CPI [Polygon Mainnet] // ================================= // setChainlinkToken(0x53E0bca35eC356BD5ddDFebbD1Fc0fD03FaBad39); // time_contract = BokkyPooBahsDateTimeContract(0x998da4fCB229Db1AA84395ef6f0c6be6Ef3dbE58); // oracle = 0x9B44870bcc35734c08e40F847cC068c0bA618194; // jobId = "8107f18343a24980b2fe7d3c8f32630f"; // fee = 1e17; // 0.1 LINK // CPI [Polygon Mumbai] // ================================= setChainlinkToken(0x326C977E6efc84E512bB9C30f76E30c160eD06FB); time_contract = BokkyPooBahsDateTimeContract(0x2Dd1B4D4548aCCeA497050619965f91f78b3b532); oracle = 0x3c30c5c415B2410326297F0f65f5Cbb32f3aefCc; jobId = "32c3e7b12fe44665a4e2bb87aa9779af"; fee = 1e17; // 0.1 LINK // Add the first observation cpi_observations.push(CPIObservation( 2021, 12, cpi_last, peg_price_last, 1642208400 // Dec data observed on Jan 15 2021 )); // Add the second observation cpi_observations.push(CPIObservation( 2022, 1, cpi_target, peg_price_target, 1644886800 // Jan data observed on Feb 15 2022 )); } /* ========== VIEWS ========== */ function upcomingCPIParams() public view returns ( uint256 upcoming_year, uint256 upcoming_month, uint256 upcoming_timestamp ) { if (stored_month == 12) { upcoming_year = stored_year + 1; upcoming_month = 1; } else { upcoming_year = stored_year; upcoming_month = stored_month + 1; } // Data is usually released by the 15th day of the next month (fulfill_ready_day) // https://www.usinflationcalculator.com/inflation/consumer-price-index-release-schedule/ upcoming_timestamp = time_contract.timestampFromDate(upcoming_year, upcoming_month, fulfill_ready_day); } // Display the upcoming CPI month function upcomingSerie() external view returns (string memory serie_name) { // Get the upcoming CPI params (uint256 upcoming_year, uint256 upcoming_month, ) = upcomingCPIParams(); // Convert to a string return string(abi.encodePacked("CUSR0000SA0", " ", month_names[upcoming_month], " ", Strings.toString(upcoming_year))); } // Delta between the current and previous peg prices function currDeltaFracE6() public view returns (int256) { return int256(((peg_price_target - peg_price_last) * 1e6) / peg_price_last); } // Absolute value of the delta between the current and previous peg prices function currDeltaFracAbsE6() public view returns (uint256) { int256 curr_delta_frac = currDeltaFracE6(); if (curr_delta_frac > 0) return uint256(curr_delta_frac); else return uint256(-curr_delta_frac); } // Current peg price in E18, accounting for the ramping function currPegPrice() external view returns (uint256) { uint256 elapsed_time = block.timestamp - lastUpdateTime; if (elapsed_time >= ramp_period) { return peg_price_target; } else { // Calculate the fraction of the delta to use, based on the elapsed time // Can be negative in case of deflation (that never happens right :]) int256 fractional_price_delta = (int256(peg_price_target - peg_price_last) * int256(elapsed_time)) / int256(ramp_period); return uint256(int256(peg_price_last) + int256(fractional_price_delta)); } } /* ========== MUTATIVE ========== */ // Fetch the CPI data from the Chainlink oracle function requestCPIData() external onlyByOwnGovBot returns (bytes32 requestId) { Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfill.selector); // Get the upcoming CPI params (uint256 upcoming_year, uint256 upcoming_month, uint256 upcoming_timestamp) = upcomingCPIParams(); // Don't update too fast require(block.timestamp >= upcoming_timestamp, "Too early"); request.add("serie", "CUSR0000SA0"); // CPI-U: https://data.bls.gov/timeseries/CUSR0000SA0 request.add("month", month_names[upcoming_month]); request.add("year", Strings.toString(upcoming_year)); return sendChainlinkRequestTo(oracle, request, fee); } /** * Callback function */ // Called by the Chainlink oracle function fulfill(bytes32 _requestId, uint256 result) public recordChainlinkFulfillment(_requestId) { // Set the stored CPI and price to the old targets cpi_last = cpi_target; peg_price_last = peg_price_target; // Set the target CPI and price based on the results cpi_target = result; peg_price_target = (peg_price_last * cpi_target) / cpi_last; // Make sure the delta isn't too large require(currDeltaFracAbsE6() <= max_delta_frac, "Delta too high"); // Update the timestamp lastUpdateTime = block.timestamp; // Update the year and month (uint256 result_year, uint256 result_month, ) = upcomingCPIParams(); stored_year = result_year; stored_month = result_month; // Update the future ramp period, if applicable // A ramp cannot be updated mid-month as it will mess up the last_price math; ramp_period = future_ramp_period; // Add the observation cpi_observations.push(CPIObservation( result_year, result_month, cpi_target, peg_price_target, block.timestamp )); emit CPIUpdated(result_year, result_month, result, peg_price_target, ramp_period); } function cancelRequest( bytes32 _requestId, uint256 _payment, bytes4 _callbackFunc, uint256 _expiration ) external onlyByOwnGovBot { cancelChainlinkRequest(_requestId, _payment, _callbackFunc, _expiration); } /* ========== RESTRICTED FUNCTIONS ========== */ function setTimelock(address _new_timelock_address) external onlyByOwnGov { timelock_address = _new_timelock_address; } function setBot(address _new_bot_address) external onlyByOwnGov { bot_address = _new_bot_address; } function setOracleInfo(address _oracle, bytes32 _jobId, uint256 _fee) external onlyByOwnGov { oracle = _oracle; jobId = _jobId; fee = _fee; } function setMaxDeltaFrac(uint256 _max_delta_frac) external onlyByOwnGov { max_delta_frac = _max_delta_frac; } function setFulfillReadyDay(uint256 _fulfill_ready_day) external onlyByOwnGov { fulfill_ready_day = _fulfill_ready_day; } function setFutureRampPeriod(uint256 _future_ramp_period) external onlyByOwnGov { future_ramp_period = _future_ramp_period; // In sec } // Mainly for recovering LINK function recoverERC20(address tokenAddress, uint256 tokenAmount) external onlyByOwnGov { // Only the owner address can ever receive the recovery withdrawal TransferHelper.safeTransfer(tokenAddress, owner, tokenAmount); } /* ========== EVENTS ========== */ event CPIUpdated(uint256 year, uint256 month, uint256 result, uint256 peg_price_target, uint256 ramp_period); } // File contracts/Uniswap_V2_TWAMM/core/interfaces/IUniswapV2PairV5.sol interface IUniswapV2PairV5 { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function price0CumulativeLast() external view returns (uint); function price1CumulativeLast() external view returns (uint); function kLast() external view returns (uint); function mint(address to) external returns (uint liquidity); function burn(address to) external returns (uint amount0, uint amount1); function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; function skim(address to) external; function sync() external; function initialize(address, address) external; } // File contracts/Uniswap_V2_TWAMM/core/interfaces/IUniV2TWAMMPair.sol // ==================================================================== // | ______ _______ | // | / _____________ __ __ / ____(_____ ____ _____ ________ | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ | // | | // ==================================================================== // ========================= IUniV2TWAMMPair ========================== // ==================================================================== // TWAMM LP Pair Interface // Inspired by https://www.paradigm.xyz/2021/07/twamm // https://github.com/para-dave/twamm // Frax Finance: https://github.com/FraxFinance // Primary Author(s) // Rich Gee: https://github.com/zer0blockchain // Dennis: https://github.com/denett // Reviewer(s) / Contributor(s) // Travis Moore: https://github.com/FortisFortuna // Sam Kazemian: https://github.com/samkazemian interface IUniV2TWAMMPair is IUniswapV2PairV5 { // TWAMM event LongTermSwap0To1(address indexed addr, uint256 orderId, uint256 amount0In, uint256 numberOfTimeIntervals); event LongTermSwap1To0(address indexed addr, uint256 orderId, uint256 amount1In, uint256 numberOfTimeIntervals); event CancelLongTermOrder(address indexed addr, uint256 orderId, address sellToken, uint256 unsoldAmount, address buyToken, uint256 purchasedAmount); event WithdrawProceedsFromLongTermOrder(address indexed addr, uint256 orderId, address indexed proceedToken, uint256 proceeds, bool orderExpired); function longTermSwapFrom0To1(uint256 amount0In, uint256 numberOfTimeIntervals) external returns (uint256 orderId); function longTermSwapFrom1To0(uint256 amount1In, uint256 numberOfTimeIntervals) external returns (uint256 orderId); function cancelLongTermSwap(uint256 orderId) external; function withdrawProceedsFromLongTermSwap(uint256 orderId) external returns (bool is_expired, address rewardTkn, uint256 totalReward); function executeVirtualOrders(uint256 blockTimestamp) external; function orderTimeInterval() external returns (uint256); function getTWAPHistoryLength() external view returns (uint); function getTwammReserves() external view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast, uint112 _twammReserve0, uint112 _twammReserve1); function getReserveAfterTwamm(uint256 blockTimestamp) external view returns (uint112 _reserve0, uint112 _reserve1, uint256 lastVirtualOrderTimestamp, uint112 _twammReserve0, uint112 _twammReserve1); function getNextOrderID() external view returns (uint256); function getOrderIDsForUser(address user) external view returns (uint256[] memory); function getOrderIDsForUserLength(address user) external view returns (uint256); // function getDetailedOrdersForUser(address user, uint256 offset, uint256 limit) external view returns (LongTermOrdersLib.Order[] memory detailed_orders); function twammUpToDate() external view returns (bool); function getTwammState() external view returns (uint256 token0Rate, uint256 token1Rate, uint256 lastVirtualOrderTimestamp, uint256 orderTimeInterval_rtn, uint256 rewardFactorPool0, uint256 rewardFactorPool1); function getTwammSalesRateEnding(uint256 _blockTimestamp) external view returns (uint256 orderPool0SalesRateEnding, uint256 orderPool1SalesRateEnding); function getTwammRewardFactor(uint256 _blockTimestamp) external view returns (uint256 rewardFactorPool0AtTimestamp, uint256 rewardFactorPool1AtTimestamp); function getTwammOrder(uint256 orderId) external view returns (uint256 id, uint256 expirationTimestamp, uint256 saleRate, address owner, address sellTokenAddr, address buyTokenAddr); function getTwammOrderProceedsView(uint256 orderId, uint256 blockTimestamp) external view returns (bool orderExpired, uint256 totalReward); function getTwammOrderProceeds(uint256 orderId) external returns (bool orderExpired, uint256 totalReward); function togglePauseNewSwaps() external; } // File contracts/Uniswap_V2_TWAMM/core/interfaces/IUniswapV2FactoryV5.sol interface IUniswapV2FactoryV5 { event PairCreated(address indexed token0, address indexed token1, address pair, uint); function feeTo() external view returns (address); function feeToSetter() external view returns (address); function getPair(address tokenA, address tokenB) external view returns (address pair); function allPairs(uint) external view returns (address pair); function allPairsLength() external view returns (uint); function createPair(address tokenA, address tokenB) external returns (address pair); function setFeeTo(address) external; function setFeeToSetter(address) external; } // File contracts/Uniswap_V2_TWAMM/libraries/Babylonian.sol // computes square roots using the babylonian method // https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method library Babylonian { // credit for this implementation goes to // https://github.com/abdk-consulting/abdk-libraries-solidity/blob/master/ABDKMath64x64.sol#L687 function sqrt(uint256 x) internal pure returns (uint256) { if (x == 0) return 0; // this block is equivalent to r = uint256(1) << (BitMath.mostSignificantBit(x) / 2); // however that code costs significantly more gas uint256 xx = x; uint256 r = 1; if (xx >= 0x100000000000000000000000000000000) { xx >>= 128; r <<= 64; } if (xx >= 0x10000000000000000) { xx >>= 64; r <<= 32; } if (xx >= 0x100000000) { xx >>= 32; r <<= 16; } if (xx >= 0x10000) { xx >>= 16; r <<= 8; } if (xx >= 0x100) { xx >>= 8; r <<= 4; } if (xx >= 0x10) { xx >>= 4; r <<= 2; } if (xx >= 0x8) { r <<= 1; } r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; r = (r + x / r) >> 1; // Seven iterations should be enough uint256 r1 = x / r; return (r < r1 ? r : r1); } } // File contracts/Uniswap_V2_TWAMM/libraries/FullMath.sol /// @notice Math library that facilitates multiplication and division that can have overflow of an intermediate value without any loss of precision. /// @author Adapted from https://github.com/Uniswap/uniswap-v3-core/blob/main/contracts/libraries/FullMath.sol. /// @dev Handles "phantom overflow", i.e., allows multiplication and division where an intermediate value overflows 256 bits. library FullMath { /// @notice Calculates floor(a×b÷denominator) with full precision - throws if result overflows an uint256 or denominator == 0. /// @param a The multiplicand. /// @param b The multiplier. /// @param denominator The divisor. /// @return result The 256-bit result. /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv. function mulDiv( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = a * b. // Compute the product mod 2**256 and mod 2**256 - 1, // then 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(a, b, not(0)) prod0 := mul(a, b) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { require(denominator > 0); assembly { result := div(prod0, denominator) } return result; } // Make sure the result is less than 2**256 - // also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0] - // compute remainder using mulmod. uint256 remainder; assembly { remainder := mulmod(a, b, denominator) } // Subtract 256 bit number from 512 bit number. assembly { prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator - // compute largest power of two divisor of denominator // (always >= 1). uint256 twos = uint256(-int256(denominator)) & denominator; // Divide denominator by power of two. assembly { denominator := div(denominator, twos) } // Divide [prod1 prod0] by the factors of two. assembly { prod0 := div(prod0, twos) } // Shift in bits from prod1 into prod0. For this we need // to flip `twos` such that it is 2**256 / twos - // if twos is zero, then it becomes one. assembly { twos := add(div(sub(0, twos), twos), 1) } 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 inv = (3 * denominator) ^ 2; // Now use 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. inv *= 2 - denominator * inv; // Inverse mod 2**8. inv *= 2 - denominator * inv; // Inverse mod 2**16. inv *= 2 - denominator * inv; // Inverse mod 2**32. inv *= 2 - denominator * inv; // Inverse mod 2**64. inv *= 2 - denominator * inv; // Inverse mod 2**128. inv *= 2 - denominator * inv; // 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 precoditions 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 * inv; return result; } } /// @notice Calculates ceil(a×b÷denominator) with full precision - throws if result overflows an uint256 or denominator == 0. /// @param a The multiplicand. /// @param b The multiplier. /// @param denominator The divisor. /// @return result The 256-bit result. function mulDivRoundingUp( uint256 a, uint256 b, uint256 denominator ) internal pure returns (uint256 result) { result = mulDiv(a, b, denominator); unchecked { if (mulmod(a, b, denominator) != 0) { require(result < type(uint256).max); result++; } } } } // File contracts/Uniswap_V2_TWAMM/periphery/libraries/UniswapV2LiquidityMathLibraryMini.sol // library containing some math for dealing with the liquidity shares of a pair, e.g. computing their exact value // in terms of the underlying tokens library UniswapV2LiquidityMathLibraryMini { // computes the direction and magnitude of the profit-maximizing trade // function computeProfitMaximizingTrade( // uint256 truePriceTokenA, // uint256 truePriceTokenB, // uint256 reserveA, // uint256 reserveB // ) pure internal returns (uint256 amountIn) { // bool aToB = ((reserveA * truePriceTokenB) / reserveB) < truePriceTokenA; // uint256 invariant = reserveA * reserveB; // // true price is expressed as a ratio, so both values must be non-zero // require(truePriceTokenA != 0 && truePriceTokenB != 0, "CPMT: ZERO_PRICE"); // uint256 leftSide = Babylonian.sqrt( // FullMath.mulDiv( // (invariant * 1000), // aToB ? truePriceTokenA : truePriceTokenB, // (aToB ? truePriceTokenB : truePriceTokenA) * 997 // ) // ); // uint256 rightSide = (aToB ? reserveA * 1000 : reserveB * 1000) / 997; // if (leftSide < rightSide) return (0); // // compute the amount that must be sent to move the price to the profit-maximizing price // amountIn = leftSide - rightSide; // } function computeProfitMaximizingTrade( uint256 inTokenTruePrice, uint256 outTokenTruePrice, uint256 reserveIn, uint256 reserveOut ) pure internal returns (uint256 amountIn) { uint256 invariant = reserveIn * reserveOut; // true price is expressed as a ratio, so both values must be non-zero require(inTokenTruePrice != 0 && outTokenTruePrice != 0, "CPMT: ZERO_PRICE"); uint256 leftSide = Babylonian.sqrt( FullMath.mulDiv( (invariant * 1000), inTokenTruePrice, outTokenTruePrice * 997 ) ); uint256 rightSide = (reserveIn * 1000) / 997; if (leftSide < rightSide) return (0); // compute the amount that must be sent to move the price to the profit-maximizing price amountIn = leftSide - rightSide; } } // File contracts/FPI/FPIControllerPool.sol // ==================================================================== // | ______ _______ | // | / _____________ __ __ / ____(_____ ____ _____ ________ | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ | // | | // ==================================================================== // ========================= FPIControllerPool ========================= // ==================================================================== // Makes sure FPI is targeting the CPI peg // First method is minting / redeeming with FRAX // Second is bulk TWAMM trades // Frax Finance: https://github.com/FraxFinance // Primary Author(s) // Travis Moore: https://github.com/FortisFortuna // Reviewer(s) / Contributor(s) // Sam Kazemian: https://github.com/samkazemian // Rich Gee: https://github.com/zer0blockchain // Dennis: https://github.com/denett // Jack Corddry: https://github.com/corddry contract FPIControllerPool is Owned { // Core address public timelock_address; FPI public FPI_TKN; IFrax public FRAX; IUniV2TWAMMPair public TWAMM; // Oracles AggregatorV3Interface public priceFeedFRAXUSD; AggregatorV3Interface public priceFeedFPIUSD; uint256 public chainlink_frax_usd_decimals; uint256 public chainlink_fpi_usd_decimals; CPITrackerOracle public cpiTracker; // Tracking uint256 public last_order_id_twamm; // Last TWAMM order ID that was used // AMO addresses (lend out FRAX) address[] public amos_array; mapping(address => bool) public amos; // Mapping is also used for faster verification // FRAX borrowed balances mapping(address => int256) public frax_borrowed_balances; // Amount of FRAX the contract borrowed, by AMO int256 public frax_borrowed_sum = 0; // Across all AMOs int256 public frax_borrow_cap = int256(10000000e18); // Max amount of FRAX the contract can borrow from this contract // Mint Fee Related bool public use_manual_mint_fee = true; uint256 public mint_fee_manual = 3000; // E6 uint256 public mint_fee_multiplier = 1000000; // E6 // Redeem Fee Related bool public use_manual_redeem_fee = true; uint256 public redeem_fee_manual = 3000; // E6 uint256 public redeem_fee_multiplier = 1000000; // E6 // Safety uint256 public fpi_mint_cap = 110000000e18; // 110M uint256 public peg_band_mint_redeem = 50000; // 5% uint256 public peg_band_twamm = 100000; // 10% uint256 public max_swap_frax_amt_in = 10000000e18; // 10M, mainly fat-finger precautions uint256 public max_swap_fpi_amt_in = 10000000e18; // 10M, mainly fat-finger precautions bool public mints_paused = false; bool public redeems_paused = false; // Constants for various precisions uint256 public constant PRICE_PRECISION = 1e18; uint256 public constant FEE_PRECISION = 1e6; uint256 public constant PEG_BAND_PRECISION = 1e6; // Misc bool public frax_is_token0; bool public pending_twamm_order = false; uint256 public num_twamm_intervals = 168; // Each interval is default 3600 sec (1 hr) uint256 public swap_period = 7 * 86400; // 7 days /* ========== MODIFIERS ========== */ modifier onlyByOwnGov() { require(msg.sender == owner || msg.sender == timelock_address, "Not owner or timelock"); _; } modifier validAMO(address amo_address) { require(amos[amo_address], "Invalid AMO"); _; } /* ========== CONSTRUCTOR ========== */ constructor ( address _creator_address, address _timelock_address, address[6] memory _address_pack ) Owned(_creator_address) { timelock_address = _timelock_address; // Set instances FRAX = IFrax(_address_pack[0]); FPI_TKN = FPI(_address_pack[1]); TWAMM = IUniV2TWAMMPair(_address_pack[2]); priceFeedFRAXUSD = AggregatorV3Interface(_address_pack[3]); priceFeedFPIUSD = AggregatorV3Interface(_address_pack[4]); cpiTracker = CPITrackerOracle(_address_pack[5]); // Set the oracle decimals chainlink_frax_usd_decimals = priceFeedFRAXUSD.decimals(); chainlink_fpi_usd_decimals = priceFeedFPIUSD.decimals(); // Need to know which token FRAX is (0 or 1) address token0 = TWAMM.token0(); if (token0 == address(FRAX)) frax_is_token0 = true; else frax_is_token0 = false; // Get the number of TWAMM intervals. Truncation desired num_twamm_intervals = swap_period / TWAMM.orderTimeInterval(); } /* ========== VIEWS ========== */ // Needed as a FRAX AMO function dollarBalances() public view returns (uint256 frax_val_e18, uint256 collat_val_e18) { // Dummy values here. FPI is not FRAX and should not be treated as FRAX collateral frax_val_e18 = 1e18; collat_val_e18 = 1e18; } // In Chainlink decimals function getFRAXPriceE18() public view returns (uint256) { (uint80 roundID, int price, , uint256 updatedAt, uint80 answeredInRound) = priceFeedFRAXUSD.latestRoundData(); require(price >= 0 && updatedAt!= 0 && answeredInRound >= roundID, "Invalid chainlink price"); return ((uint256(price) * 1e18) / (10 ** chainlink_frax_usd_decimals)); } // In Chainlink decimals function getFPIPriceE18() public view returns (uint256) { (uint80 roundID, int price, , uint256 updatedAt, uint80 answeredInRound) = priceFeedFPIUSD.latestRoundData(); require(price >= 0 && updatedAt!= 0 && answeredInRound >= roundID, "Invalid chainlink price"); return ((uint256(price) * 1e18) / (10 ** chainlink_fpi_usd_decimals)); } // Reserve spot price (fpi_price is dangerous / flash loan susceptible, so use carefully) function getReservesAndFPISpot() public returns (uint256 reserveFRAX, uint256 reserveFPI, uint256 fpi_price) { // Update and get the reserves TWAMM.executeVirtualOrders(block.timestamp); { (uint256 reserveA, uint256 reserveB, ) = TWAMM.getReserves(); if (frax_is_token0){ reserveFRAX = reserveA; reserveFPI = reserveB; } else { reserveFRAX = reserveB; reserveFPI = reserveA; } } // Get the TWAMM reserve spot price fpi_price = (reserveFRAX * 1e18) / reserveFPI; } // function getTwammToPegAmt() public returns (uint256 frax_in, uint256 fpi_in) { // // Update and get the reserves // (uint256 reserveFRAX, uint256 reserveFPI, uint256 reservePriceFPI) = getReservesAndFPISpot(); // // Get the CPI price // uint256 cpi_peg_price = cpiTracker.currPegPrice(); // // Sort the pricing. NOTE: IN RATIOS, NOT PRICE // uint256 truePriceFRAX = 1e18; // uint256 truePriceFPI = cpi_peg_price; // // Determine the direction // if (fpi_to_frax) { // return UniswapV2LiquidityMathLibraryMini.computeProfitMaximizingTrade( // truePriceFPI, truePriceFRAX, // reserveFPI, reserveFRAX // ); // } // else { // return UniswapV2LiquidityMathLibraryMini.computeProfitMaximizingTrade( // truePriceFRAX, truePriceFPI, // reserveFRAX, reserveFPI // ); // } // } // In E6 function mint_fee() public view returns (uint256 fee) { if (use_manual_mint_fee) fee = mint_fee_manual; else { // For future variable fees fee = 0; // Apply the multiplier fee = (fee * mint_fee_multiplier) / 1e6; } } // In E6 function redeem_fee() public view returns (uint256 fee) { if (use_manual_redeem_fee) fee = redeem_fee_manual; else { // For future variable fees fee = 0; // Apply the multiplier fee = (fee * redeem_fee_multiplier) / 1e6; } } // Get some info about the peg status function pegStatusMntRdm() public view returns (uint256 cpi_peg_price, uint256 diff_frac_abs, bool within_range) { uint256 fpi_price = getFPIPriceE18(); cpi_peg_price = cpiTracker.currPegPrice(); if (fpi_price > cpi_peg_price){ diff_frac_abs = ((fpi_price - cpi_peg_price) * PEG_BAND_PRECISION) / fpi_price; } else { diff_frac_abs = ((cpi_peg_price - fpi_price) * PEG_BAND_PRECISION) / fpi_price; } within_range = (diff_frac_abs <= peg_band_mint_redeem); } // Get additional info about the peg status function price_info() public view returns ( int256 collat_imbalance, uint256 cpi_peg_price, uint256 fpi_price, uint256 price_diff_frac_abs ) { fpi_price = getFPIPriceE18(); cpi_peg_price = cpiTracker.currPegPrice(); uint256 fpi_supply = FPI_TKN.totalSupply(); if (fpi_price > cpi_peg_price){ collat_imbalance = int256(((fpi_price - cpi_peg_price) * fpi_supply) / PRICE_PRECISION); price_diff_frac_abs = ((fpi_price - cpi_peg_price) * PEG_BAND_PRECISION) / fpi_price; } else { collat_imbalance = -1 * int256(((cpi_peg_price - fpi_price) * fpi_supply) / PRICE_PRECISION); price_diff_frac_abs = ((cpi_peg_price - fpi_price) * PEG_BAND_PRECISION) / fpi_price; } } /* ========== MUTATIVE ========== */ // Calculate Mint FPI with FRAX function calcMintFPI(uint256 frax_in, uint256 min_fpi_out) public view returns (uint256 fpi_out) { require(!mints_paused, "Mints paused"); // Fetch the CPI price and other info (uint256 cpi_peg_price, , bool within_range) = pegStatusMntRdm(); // Make sure the peg is within range for minting // Helps combat oracle errors and megadumping require(within_range, "Peg band [Mint]"); // Calculate the amount of FPI that the incoming FRAX should give fpi_out = (frax_in * PRICE_PRECISION) / cpi_peg_price; // Apply the fee fpi_out -= (fpi_out * mint_fee()) / FEE_PRECISION; // Make sure enough FPI is generated require(fpi_out >= min_fpi_out, "Slippage [Mint]"); // Check the mint cap require(FPI_TKN.totalSupply() + fpi_out <= fpi_mint_cap, "FPI mint cap"); } // Mint FPI with FRAX function mintFPI(uint256 frax_in, uint256 min_fpi_out) external returns (uint256 fpi_out) { fpi_out = calcMintFPI(frax_in, min_fpi_out); // Pull in the FRAX TransferHelper.safeTransferFrom(address(FRAX), msg.sender, address(this), frax_in); // Mint FPI to the sender FPI_TKN.minter_mint(msg.sender, fpi_out); emit FPIMinted(frax_in, fpi_out); } // Calculate Redeem FPI for FRAX function calcRedeemFPI(uint256 fpi_in, uint256 min_frax_out) public view returns (uint256 frax_out) { require(!redeems_paused, "Redeems paused"); // Fetch the CPI price and other info (uint256 cpi_peg_price, , bool within_range) = pegStatusMntRdm(); // Make sure the peg is within range for minting // Helps combat oracle errors and megadumping require(within_range, "Peg band [Redeem]"); // Calculate the amount of FRAX that the incoming FPI should give frax_out = (fpi_in * cpi_peg_price) / PRICE_PRECISION; // Apply the fee frax_out -= (frax_out * redeem_fee()) / FEE_PRECISION; // Make sure enough FRAX is generated require(frax_out >= min_frax_out, "Slippage [Redeem]"); } // Redeem FPI for FRAX function redeemFPI(uint256 fpi_in, uint256 min_frax_out) external returns (uint256 frax_out) { frax_out = calcRedeemFPI(fpi_in, min_frax_out); // Pull in the FPI TransferHelper.safeTransferFrom(address(FPI_TKN), msg.sender, address(this), fpi_in); // Give FRAX to the sender TransferHelper.safeTransfer(address(FRAX), msg.sender, frax_out); emit FPIRedeemed(fpi_in, frax_out); } // Use the TWAMM for bulk peg corrections function twammManual(uint256 frax_sell_amt, uint256 fpi_sell_amt, uint256 override_intervals) external onlyByOwnGov returns (uint256 frax_to_use, uint256 fpi_to_use) { // Make sure only one direction occurs require(!((frax_sell_amt > 0) && (fpi_sell_amt > 0)), "Can only sell in one direction"); // Update and get the reserves // longTermSwapFrom0to1 and longTermSwapFrom1To0 do it automatically // TWAMM.executeVirtualOrders(block.timestamp); // Cancel the previous order (if any) and collect any leftover tokens if (pending_twamm_order) TWAMM.cancelLongTermSwap(last_order_id_twamm); // Now calculate the imbalance after the burn (, , , uint256 price_diff_abs) = price_info(); // Make sure the FPI oracle price hasn't moved away too much from the target peg price require(price_diff_abs <= peg_band_twamm, "Peg band [TWAMM]"); // Create a new order last_order_id_twamm = TWAMM.getNextOrderID(); { if (fpi_sell_amt > 0) { // Mint FPI and sell for FRAX // -------------------------------- fpi_to_use = fpi_sell_amt; // Make sure nonzero require(fpi_to_use > 0, "FPI sold must be nonzero"); // Safety check require(fpi_to_use <= max_swap_fpi_amt_in, "Too much FPI sold"); // Mint some FPI FPI_TKN.minter_mint(address(this), fpi_to_use); // Approve FPI first FPI_TKN.approve(address(TWAMM), fpi_to_use); // Sell FPI for FRAX if (frax_is_token0) { TWAMM.longTermSwapFrom1To0(fpi_to_use, override_intervals > 0 ? override_intervals : num_twamm_intervals); } else { TWAMM.longTermSwapFrom0To1(fpi_to_use, override_intervals > 0 ? override_intervals : num_twamm_intervals); } } else { // Use FRAX to buy FPI // -------------------------------- frax_to_use = frax_sell_amt; // Make sure nonzero require(frax_to_use > 0, "FRAX sold must be nonzero"); // Safety check require(frax_to_use <= max_swap_frax_amt_in, "Too much FRAX sold"); // Approve FRAX first FRAX.approve(address(TWAMM), frax_to_use); // Sell FRAX for FPI if (frax_is_token0) { TWAMM.longTermSwapFrom0To1(frax_to_use, override_intervals > 0 ? override_intervals : num_twamm_intervals); } else { TWAMM.longTermSwapFrom1To0(frax_to_use, override_intervals > 0 ? override_intervals : num_twamm_intervals); } } } // Mark that there is a pending order pending_twamm_order = true; emit TWAMMedToPeg(last_order_id_twamm, frax_to_use, fpi_to_use, block.timestamp); } function cancelCurrTWAMMOrder(uint256 order_id_override) public onlyByOwnGov { // Cancel the order TWAMM.cancelLongTermSwap(order_id_override == 0 ? last_order_id_twamm : order_id_override); // Clear the pending order indicator pending_twamm_order = false; } function collectCurrTWAMMProceeds(uint256 order_id_override) external onlyByOwnGov { // Withdraw current proceeds (bool is_expired, , ) = TWAMM.withdrawProceedsFromLongTermSwap(order_id_override == 0 ? last_order_id_twamm : order_id_override); // If using the last_order_id_twamm and it is expired, clear the pending order indicator if (is_expired && (order_id_override == 0)) pending_twamm_order = false; } /* ========== Burns and givebacks ========== */ // Burn unneeded or excess FPI. function burnFPI(bool burn_all, uint256 fpi_amount) public onlyByOwnGov { if (burn_all) { // Burn any leftover FPI FPI_TKN.burn(FPI_TKN.balanceOf(address(this))); } else FPI_TKN.burn(fpi_amount); } // ------------------------------------------------------------------ // ------------------------------ FRAX ------------------------------ // ------------------------------------------------------------------ // Lend the FRAX collateral to an AMO function giveFRAXToAMO(address destination_amo, uint256 frax_amount) external onlyByOwnGov validAMO(destination_amo) { int256 frax_amount_i256 = int256(frax_amount); // Update the balances first require((frax_borrowed_sum + frax_amount_i256) <= frax_borrow_cap, "Borrow cap"); frax_borrowed_balances[destination_amo] += frax_amount_i256; frax_borrowed_sum += frax_amount_i256; // Give the FRAX to the AMO TransferHelper.safeTransfer(address(FRAX), destination_amo, frax_amount); } // AMO gives back FRAX. Needed for proper accounting function receiveFRAXFromAMO(uint256 frax_amount) external validAMO(msg.sender) { int256 frax_amt_i256 = int256(frax_amount); // Give back first TransferHelper.safeTransferFrom(address(FRAX), msg.sender, address(this), frax_amount); // Then update the balances frax_borrowed_balances[msg.sender] -= frax_amt_i256; frax_borrowed_sum -= frax_amt_i256; } /* ========== RESTRICTED FUNCTIONS ========== */ // Adds an AMO function addAMO(address amo_address) public onlyByOwnGov { require(amo_address != address(0), "Zero address detected"); require(amos[amo_address] == false, "Address already exists"); amos[amo_address] = true; amos_array.push(amo_address); emit AMOAdded(amo_address); } // Removes an AMO function removeAMO(address amo_address) public onlyByOwnGov { require(amo_address != address(0), "Zero address detected"); require(amos[amo_address] == true, "Address nonexistant"); // Delete from the mapping delete amos[amo_address]; // 'Delete' from the array by setting the address to 0x0 for (uint i = 0; i < amos_array.length; i++){ if (amos_array[i] == amo_address) { amos_array[i] = address(0); // This will leave a null in the array and keep the indices the same break; } } emit AMORemoved(amo_address); } function setOracles(address _frax_oracle, address _fpi_oracle, address _cpi_oracle) external onlyByOwnGov { priceFeedFRAXUSD = AggregatorV3Interface(_frax_oracle); priceFeedFPIUSD = AggregatorV3Interface(_fpi_oracle); cpiTracker = CPITrackerOracle(_cpi_oracle); // Set the Chainlink oracle decimals chainlink_frax_usd_decimals = priceFeedFRAXUSD.decimals(); chainlink_fpi_usd_decimals = priceFeedFPIUSD.decimals(); } function setTWAMMAndSwapPeriod(address _twamm_addr, uint256 _swap_period) external onlyByOwnGov { // Cancel an outstanding order, if present if (pending_twamm_order) cancelCurrTWAMMOrder(last_order_id_twamm); // Change the TWAMM parameters TWAMM = IUniV2TWAMMPair(_twamm_addr); swap_period = _swap_period; num_twamm_intervals = _swap_period / TWAMM.orderTimeInterval(); } function toggleMints() external onlyByOwnGov { mints_paused = !mints_paused; } function toggleRedeems() external onlyByOwnGov { redeems_paused = !redeems_paused; } function setFraxBorrowCap(int256 _frax_borrow_cap) external onlyByOwnGov { frax_borrow_cap = _frax_borrow_cap; } function setMintCap(uint256 _fpi_mint_cap) external onlyByOwnGov { fpi_mint_cap = _fpi_mint_cap; } function setPegBands(uint256 _peg_band_mint_redeem, uint256 _peg_band_twamm) external onlyByOwnGov { peg_band_mint_redeem = _peg_band_mint_redeem; peg_band_twamm = _peg_band_twamm; } function setMintRedeemFees( bool _use_manual_mint_fee, uint256 _mint_fee_manual, uint256 _mint_fee_multiplier, bool _use_manual_redeem_fee, uint256 _redeem_fee_manual, uint256 _redeem_fee_multiplier ) external onlyByOwnGov { use_manual_mint_fee = _use_manual_mint_fee; mint_fee_manual = _mint_fee_manual; mint_fee_multiplier = _mint_fee_multiplier; use_manual_redeem_fee = _use_manual_redeem_fee; redeem_fee_manual = _redeem_fee_manual; redeem_fee_multiplier = _redeem_fee_multiplier; } function setTWAMMMaxSwapIn(uint256 _max_swap_frax_amt_in, uint256 _max_swap_fpi_amt_in) external onlyByOwnGov { max_swap_frax_amt_in = _max_swap_frax_amt_in; max_swap_fpi_amt_in = _max_swap_fpi_amt_in; } function setTimelock(address _new_timelock_address) external onlyByOwnGov { timelock_address = _new_timelock_address; } // Added to support recovering LP Rewards and other mistaken tokens from other systems to be distributed to holders function recoverERC20(address tokenAddress, uint256 tokenAmount) external onlyByOwnGov { // Only the owner address can ever receive the recovery withdrawal TransferHelper.safeTransfer(tokenAddress, owner, tokenAmount); emit RecoveredERC20(tokenAddress, tokenAmount); } /* ========== EVENTS ========== */ event AMOAdded(address amo_address); event AMORemoved(address amo_address); event RecoveredERC20(address token, uint256 amount); event FPIMinted(uint256 frax_in, uint256 fpi_out); event FPIRedeemed(uint256 fpi_in, uint256 frax_out); event TWAMMedToPeg(uint256 order_id, uint256 frax_amt, uint256 fpi_amt, uint256 timestamp); }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_creator_address","type":"address"},{"internalType":"address","name":"_timelock_address","type":"address"},{"internalType":"address[6]","name":"_address_pack","type":"address[6]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"amo_address","type":"address"}],"name":"AMOAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"amo_address","type":"address"}],"name":"AMORemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"frax_in","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fpi_out","type":"uint256"}],"name":"FPIMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"fpi_in","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"frax_out","type":"uint256"}],"name":"FPIRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RecoveredERC20","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"order_id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"frax_amt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fpi_amt","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"TWAMMedToPeg","type":"event"},{"inputs":[],"name":"FEE_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FPI_TKN","outputs":[{"internalType":"contract FPI","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FRAX","outputs":[{"internalType":"contract IFrax","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PEG_BAND_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICE_PRECISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TWAMM","outputs":[{"internalType":"contract IUniV2TWAMMPair","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"amo_address","type":"address"}],"name":"addAMO","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"amos","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"amos_array","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"burn_all","type":"bool"},{"internalType":"uint256","name":"fpi_amount","type":"uint256"}],"name":"burnFPI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"frax_in","type":"uint256"},{"internalType":"uint256","name":"min_fpi_out","type":"uint256"}],"name":"calcMintFPI","outputs":[{"internalType":"uint256","name":"fpi_out","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"fpi_in","type":"uint256"},{"internalType":"uint256","name":"min_frax_out","type":"uint256"}],"name":"calcRedeemFPI","outputs":[{"internalType":"uint256","name":"frax_out","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"order_id_override","type":"uint256"}],"name":"cancelCurrTWAMMOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"chainlink_fpi_usd_decimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainlink_frax_usd_decimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"order_id_override","type":"uint256"}],"name":"collectCurrTWAMMProceeds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cpiTracker","outputs":[{"internalType":"contract CPITrackerOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dollarBalances","outputs":[{"internalType":"uint256","name":"frax_val_e18","type":"uint256"},{"internalType":"uint256","name":"collat_val_e18","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fpi_mint_cap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"frax_borrow_cap","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"frax_borrowed_balances","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"frax_borrowed_sum","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"frax_is_token0","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFPIPriceE18","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFRAXPriceE18","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getReservesAndFPISpot","outputs":[{"internalType":"uint256","name":"reserveFRAX","type":"uint256"},{"internalType":"uint256","name":"reserveFPI","type":"uint256"},{"internalType":"uint256","name":"fpi_price","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"destination_amo","type":"address"},{"internalType":"uint256","name":"frax_amount","type":"uint256"}],"name":"giveFRAXToAMO","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"last_order_id_twamm","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"max_swap_fpi_amt_in","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"max_swap_frax_amt_in","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"frax_in","type":"uint256"},{"internalType":"uint256","name":"min_fpi_out","type":"uint256"}],"name":"mintFPI","outputs":[{"internalType":"uint256","name":"fpi_out","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mint_fee","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mint_fee_manual","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mint_fee_multiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mints_paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"num_twamm_intervals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pegStatusMntRdm","outputs":[{"internalType":"uint256","name":"cpi_peg_price","type":"uint256"},{"internalType":"uint256","name":"diff_frac_abs","type":"uint256"},{"internalType":"bool","name":"within_range","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"peg_band_mint_redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"peg_band_twamm","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pending_twamm_order","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeedFPIUSD","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeedFRAXUSD","outputs":[{"internalType":"contract AggregatorV3Interface","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price_info","outputs":[{"internalType":"int256","name":"collat_imbalance","type":"int256"},{"internalType":"uint256","name":"cpi_peg_price","type":"uint256"},{"internalType":"uint256","name":"fpi_price","type":"uint256"},{"internalType":"uint256","name":"price_diff_frac_abs","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"frax_amount","type":"uint256"}],"name":"receiveFRAXFromAMO","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"name":"recoverERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"fpi_in","type":"uint256"},{"internalType":"uint256","name":"min_frax_out","type":"uint256"}],"name":"redeemFPI","outputs":[{"internalType":"uint256","name":"frax_out","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"redeem_fee","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"redeem_fee_manual","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"redeem_fee_multiplier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"redeems_paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"amo_address","type":"address"}],"name":"removeAMO","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int256","name":"_frax_borrow_cap","type":"int256"}],"name":"setFraxBorrowCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_fpi_mint_cap","type":"uint256"}],"name":"setMintCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_use_manual_mint_fee","type":"bool"},{"internalType":"uint256","name":"_mint_fee_manual","type":"uint256"},{"internalType":"uint256","name":"_mint_fee_multiplier","type":"uint256"},{"internalType":"bool","name":"_use_manual_redeem_fee","type":"bool"},{"internalType":"uint256","name":"_redeem_fee_manual","type":"uint256"},{"internalType":"uint256","name":"_redeem_fee_multiplier","type":"uint256"}],"name":"setMintRedeemFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_frax_oracle","type":"address"},{"internalType":"address","name":"_fpi_oracle","type":"address"},{"internalType":"address","name":"_cpi_oracle","type":"address"}],"name":"setOracles","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_peg_band_mint_redeem","type":"uint256"},{"internalType":"uint256","name":"_peg_band_twamm","type":"uint256"}],"name":"setPegBands","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_twamm_addr","type":"address"},{"internalType":"uint256","name":"_swap_period","type":"uint256"}],"name":"setTWAMMAndSwapPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_max_swap_frax_amt_in","type":"uint256"},{"internalType":"uint256","name":"_max_swap_fpi_amt_in","type":"uint256"}],"name":"setTWAMMMaxSwapIn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_new_timelock_address","type":"address"}],"name":"setTimelock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swap_period","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"timelock_address","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"toggleMints","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"toggleRedeems","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"frax_sell_amt","type":"uint256"},{"internalType":"uint256","name":"fpi_sell_amt","type":"uint256"},{"internalType":"uint256","name":"override_intervals","type":"uint256"}],"name":"twammManual","outputs":[{"internalType":"uint256","name":"frax_to_use","type":"uint256"},{"internalType":"uint256","name":"fpi_to_use","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"use_manual_mint_fee","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"use_manual_redeem_fee","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040526000600f556a084595161401484a000000601081905560118054600160ff199182168117909255610bb86012819055620f42406013819055601480549093169093179091556015556016556a5afd67f2dc0e1b2e00000060175561c350601855620186a0601955601a819055601b55601c805463ff00ffff1916905560a8601d5562093a80601e553480156200009957600080fd5b5060405162004b4b38038062004b4b833981016040819052620000bc916200045a565b826001600160a01b038116620001185760405162461bcd60e51b815260206004820152601960248201527f4f776e657220616464726573732063616e6e6f74206265203000000000000000604482015260640160405180910390fd5b600080546001600160a01b0319166001600160a01b03831690811782556040805192835260208301919091527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a150600280546001600160a01b03199081166001600160a01b0385811691909117909255825160048054831691841691909117815560208085015160038054851691861691909117905560408086015160058054861691871691909117905560608601516006805486169187169182179055608087015160078054871691881691909117905560a0870151600a8054909616961695909517909355825163313ce56760e01b8152925163313ce5679380840193908290030181865afa1580156200023c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000262919062000511565b60ff166008556007546040805163313ce56760e01b815290516001600160a01b039092169163313ce567916004808201926020929091908290030181865afa158015620002b3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002d9919062000511565b60ff1660095560055460408051630dfe168160e01b815290516000926001600160a01b031691630dfe16819160048083019260209291908290030181865afa1580156200032a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200035091906200053d565b6004549091506001600160a01b03908116908216036200038157601c805462ff00001916620100001790556200038e565b601c805462ff0000191690555b600560009054906101000a90046001600160a01b03166001600160a01b031663748fc63b6040518163ffffffff1660e01b81526004016020604051808303816000875af1158015620003e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200040a91906200055b565b601e5462000419919062000575565b601d55506200059892505050565b80516001600160a01b03811681146200043f57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60008060006101008085870312156200047257600080fd5b6200047d8562000427565b935060206200048e81870162000427565b935086605f870112620004a057600080fd5b60405160c081016001600160401b0381118282101715620004c557620004c562000444565b604052918601918088841115620004db57600080fd5b604088015b848110156200050257620004f48162000427565b8252908301908301620004e0565b50508093505050509250925092565b6000602082840312156200052457600080fd5b815160ff811681146200053657600080fd5b9392505050565b6000602082840312156200055057600080fd5b620005368262000427565b6000602082840312156200056e57600080fd5b5051919050565b6000826200059357634e487b7160e01b600052601260045260246000fd5b500490565b6145a380620005a86000396000f3fe608060405234801561001057600080fd5b50600436106104715760003560e01c80638980f11f11610250578063ba92341e11610150578063d9ebcc2f116100c8578063e63a391f11610097578063ea36648a1161007c578063ea36648a14610964578063eb99aff814610981578063ef71c765146109a157600080fd5b8063e63a391f14610964578063e8d5931d1461096e57600080fd5b8063d9ebcc2f14610927578063da610fcf1461092f578063dc6663c714610937578063e24ab97b1461095757600080fd5b8063bf6a89a21161011f578063c70b6ad111610104578063c70b6ad11461090d578063cd080fbd14610915578063d578660a1461091e57600080fd5b8063bf6a89a2146108e7578063c5a36df1146108fa57600080fd5b8063ba92341e1461086c578063bc3d5a8e1461088c578063bda767ab146108b1578063bdacb303146108d457600080fd5b8063a2b2d0e9116101e3578063a7c027da116101b2578063b0e4556f11610197578063b0e4556f1461083a578063b565c0cb1461085a578063b5d7684b1461086357600080fd5b8063a7c027da1461081a578063ac12d5971461082d57600080fd5b8063a2b2d0e9146107ac578063a42b4b25146107d4578063a4c3e73c146107e7578063a63b39e91461080757600080fd5b80639238c0ac1161021f5780639238c0ac1461077857806395082d25146107815780639c97ca1b146107905780639fc397e3146107a357600080fd5b80638980f11f146107295780638da5cb5b1461073c57806390f749c71461075c578063919e06ce1461076557600080fd5b806350fc60cb11610376578063694033f2116102ee57806382cd8713116102bd57806386c8c345116102a257806386c8c345146106e3578063882c95c1146106f657806388b93d9a1461071657600080fd5b806382cd8713146106b75780638583f21c146106da57600080fd5b8063694033f2146106955780636e7813ff1461069e57806379ba5097146106a657806379df3933146106ae57600080fd5b80636195e1f11161034557806365525bf61161032a57806365525bf61461066557806367694bae146106795780636830f5711461068257600080fd5b80636195e1f114610653578063631a5a171461065c57600080fd5b806350fc60cb146105ed57806353a47bb7146106005780635592e9f514610620578063608984611461064057600080fd5b80632f7e992f116104095780633ae2e4a3116103d85780634608fd46116103bd5780634608fd46146105ba57806349696b20146105c75780634d6f9ef2146105da57600080fd5b80633ae2e4a3146105945780634070a0c9146105a757600080fd5b80632f7e992f1461056757806330fd8a461461057057806335f77feb146105825780633a0319d71461058b57600080fd5b80631627540c116104455780631627540c146104dc5780631937bdf9146104ef5780631eaa95321461050f5780632141203e1461052257600080fd5b8062aa08fd1461047657806309761c7e1461048b57806309d32681146104a6578063152129b2146104b9575b600080fd5b610489610484366004613e17565b6109a9565b005b610493610aa5565b6040519081526020015b60405180910390f35b6104896104b4366004613e95565b610c14565b601c546104cc9062010000900460ff1681565b604051901515815260200161049d565b6104896104ea366004613ee0565b610e34565b6104936104fd366004613ee0565b600e6020526000908152604090205481565b61049361051d366004613f04565b610f55565b6007546105429073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161049d565b61049360155481565b601c546104cc90610100900460ff1681565b610493601b5481565b610493601a5481565b6104936105a2366004613f04565b6110fe565b6104896105b5366004613f26565b6113a2565b6011546104cc9060ff1681565b6105426105d5366004613f26565b61144a565b6104936105e8366004613f04565b611481565b6104896105fb366004613f26565b611580565b6001546105429073ffffffffffffffffffffffffffffffffffffffff1681565b600a546105429073ffffffffffffffffffffffffffffffffffffffff1681565b61048961064e366004613f26565b611628565b61049360125481565b61049360135481565b601c546104cc906301000000900460ff1681565b61049360195481565b610489610690366004613f3f565b61170a565b61049360185481565b610493611937565b610489611971565b61049360085481565b6106bf611abc565b6040805193845260208401929092529082015260600161049d565b610493601e5481565b6104896106f1366004613f6b565b611c3b565b6003546105429073ffffffffffffffffffffffffffffffffffffffff1681565b610489610724366004613f26565b611e2d565b610489610737366004613f3f565b611fa2565b6000546105429073ffffffffffffffffffffffffffffffffffffffff1681565b61049360165481565b610489610773366004613ee0565b6120bd565b610493601d5481565b610493670de0b6b3a764000081565b61048961079e366004613f3f565b6123d3565b610493600f5481565b6107b4612566565b60408051948552602085019390935291830152606082015260800161049d565b6104896107e2366004613f04565b61277b565b670de0b6b3a7640000805b6040805192835260208301919091520161049d565b6107f2610815366004613f89565b612829565b610489610828366004613ee0565b6130d5565b6014546104cc9060ff1681565b6004546105429073ffffffffffffffffffffffffffffffffffffffff1681565b61049360095481565b61049360105481565b6005546105429073ffffffffffffffffffffffffffffffffffffffff1681565b61089461335e565b60408051938452602084019290925215159082015260600161049d565b6104cc6108bf366004613ee0565b600d6020526000908152604090205460ff1681565b6104896108e2366004613ee0565b613467565b6104896108f5366004613f26565b613551565b610493610908366004613f04565b61369d565b61048961372b565b610493600b5481565b61049360175481565b610493613800565b61049361394a565b6002546105429073ffffffffffffffffffffffffffffffffffffffff1681565b601c546104cc9060ff1681565b610493620f424081565b61048961097c366004613f04565b613975565b6006546105429073ffffffffffffffffffffffffffffffffffffffff1681565b610489613a23565b60005473ffffffffffffffffffffffffffffffffffffffff163314806109e6575060025473ffffffffffffffffffffffffffffffffffffffff1633145b610a51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b000000000000000000000060448201526064015b60405180910390fd5b601180549615157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00978816179055601294909455601392909255601480549115159190941617909255601591909155601655565b6000806000806000600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015610b1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3e9190613fd4565b94509450509350935060008312158015610b5757508115155b8015610b7b57508369ffffffffffffffffffff168169ffffffffffffffffffff1610155b610be1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c696420636861696e6c696e6b2070726963650000000000000000006044820152606401610a48565b600854610bef90600a614175565b610c0184670de0b6b3a7640000614181565b610c0b91906141be565b94505050505090565b60005473ffffffffffffffffffffffffffffffffffffffff16331480610c51575060025473ffffffffffffffffffffffffffffffffffffffff1633145b610cb7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b6006805473ffffffffffffffffffffffffffffffffffffffff8086167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316811790935560078054868316908416179055600a805491851691909216179055604080517f313ce567000000000000000000000000000000000000000000000000000000008152905163313ce567916004808201926020929091908290030181865afa158015610d6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d8f91906141f9565b60ff16600855600754604080517f313ce567000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9092169163313ce567916004808201926020929091908290030181865afa158015610e05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e2991906141f9565b60ff16600955505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610edb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201527f6f726d207468697320616374696f6e00000000000000000000000000000000006064820152608401610a48565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22906020015b60405180910390a150565b601c54600090610100900460ff1615610fca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f52656465656d73207061757365640000000000000000000000000000000000006044820152606401610a48565b600080610fd561335e565b925050915080611041576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f5065672062616e64205b52656465656d5d0000000000000000000000000000006044820152606401610a48565b670de0b6b3a76400006110548387614181565b61105e91906141be565b9250620f424061106c611937565b6110769085614181565b61108091906141be565b61108a908461421c565b9250838310156110f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f536c697070616765205b52656465656d5d0000000000000000000000000000006044820152606401610a48565b505092915050565b601c5460009060ff161561116e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4d696e74732070617573656400000000000000000000000000000000000000006044820152606401610a48565b60008061117961335e565b9250509150806111e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5065672062616e64205b4d696e745d00000000000000000000000000000000006044820152606401610a48565b816111f8670de0b6b3a764000087614181565b61120291906141be565b9250620f424061121061394a565b61121a9085614181565b61122491906141be565b61122e908461421c565b92508383101561129a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f536c697070616765205b4d696e745d00000000000000000000000000000000006044820152606401610a48565b601754600354604080517f18160ddd0000000000000000000000000000000000000000000000000000000081529051869273ffffffffffffffffffffffffffffffffffffffff16916318160ddd9160048083019260209291908290030181865afa15801561130c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113309190614233565b61133a919061424c565b11156110f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f465049206d696e742063617000000000000000000000000000000000000000006044820152606401610a48565b60005473ffffffffffffffffffffffffffffffffffffffff163314806113df575060025473ffffffffffffffffffffffffffffffffffffffff1633145b611445576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b601755565b600c818154811061145a57600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b600061148d83836110fe565b6004549091506114b59073ffffffffffffffffffffffffffffffffffffffff16333086613b00565b6003546040517f6a257ebc0000000000000000000000000000000000000000000000000000000081523360048201526024810183905273ffffffffffffffffffffffffffffffffffffffff90911690636a257ebc90604401600060405180830381600087803b15801561152757600080fd5b505af115801561153b573d6000803e3d6000fd5b505060408051868152602081018590527ff4c708dad0640bb97b06e573b39b194c40301c581997805cbc86390ace5848c793500190505b60405180910390a192915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314806115bd575060025473ffffffffffffffffffffffffffffffffffffffff1633145b611623576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b601055565b336000818152600d602052604090205460ff166116a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f496e76616c696420414d4f0000000000000000000000000000000000000000006044820152606401610a48565b60045482906116c89073ffffffffffffffffffffffffffffffffffffffff16333084613b00565b336000908152600e6020526040812080548392906116e7908490614264565b9250508190555080600f60008282546117009190614264565b9091555050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611747575060025473ffffffffffffffffffffffffffffffffffffffff1633145b6117ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600d6020526040902054829060ff1661183e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f496e76616c696420414d4f0000000000000000000000000000000000000000006044820152606401610a48565b601054600f548391906118529083906142d8565b13156118ba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f426f72726f7720636170000000000000000000000000000000000000000000006044820152606401610a48565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600e6020526040812080548392906118ef9084906142d8565b9250508190555080600f600082825461190891906142d8565b90915550506004546119319073ffffffffffffffffffffffffffffffffffffffff168585613c96565b50505050565b60145460009060ff161561194c575060155490565b60009050620f4240601654826119629190614181565b61196c91906141be565b905090565b60015473ffffffffffffffffffffffffffffffffffffffff163314611a18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527f2063616e20616363657074206f776e65727368697000000000000000000000006064820152608401610a48565b6000546001546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160018054600080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b6005546040517f2e0ae3750000000000000000000000000000000000000000000000000000000081524260048201526000918291829173ffffffffffffffffffffffffffffffffffffffff1690632e0ae37590602401600060405180830381600087803b158015611b2c57600080fd5b505af1158015611b40573d6000803e3d6000fd5b50505050600080600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611bb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd8919061436a565b50601c546dffffffffffffffffffffffffffff92831694509116915062010000900460ff1615611c0d57819450809350611c14565b8094508193505b50829050611c2a84670de0b6b3a7640000614181565b611c3491906141be565b9050909192565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611c78575060025473ffffffffffffffffffffffffffffffffffffffff1633145b611cde576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b8115611dd2576003546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906342966c689082906370a0823190602401602060405180830381865afa158015611d5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d7e9190614233565b6040518263ffffffff1660e01b8152600401611d9c91815260200190565b600060405180830381600087803b158015611db657600080fd5b505af1158015611dca573d6000803e3d6000fd5b505050505050565b6003546040517f42966c680000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906342966c6890602401611d9c565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611e6a575060025473ffffffffffffffffffffffffffffffffffffffff1633145b611ed0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b60055460009073ffffffffffffffffffffffffffffffffffffffff166381fd0a468315611efd5783611f01565b600b545b6040518263ffffffff1660e01b8152600401611f1f91815260200190565b6060604051808303816000875af1158015611f3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f6291906143af565b50509050808015611f71575081155b15611e2957601c80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff1690555050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611fdf575060025473ffffffffffffffffffffffffffffffffffffffff1633145b612045576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b60005461206a90839073ffffffffffffffffffffffffffffffffffffffff1683613c96565b6040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527f55350610fe57096d8c0ffa30beede987326bccfcb0b4415804164d0dd50ce8b1910160405180910390a15050565b60005473ffffffffffffffffffffffffffffffffffffffff163314806120fa575060025473ffffffffffffffffffffffffffffffffffffffff1633145b612160576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b73ffffffffffffffffffffffffffffffffffffffff81166121dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f5a65726f206164647265737320646574656374656400000000000000000000006044820152606401610a48565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d602052604090205460ff161515600114612271576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f41646472657373206e6f6e6578697374616e74000000000000000000000000006044820152606401610a48565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d6020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b600c5481101561238c578173ffffffffffffffffffffffffffffffffffffffff16600c82815481106122f1576122f16143f2565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff160361237a576000600c828154811061232d5761232d6143f2565b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061238c565b8061238481614421565b9150506122bd565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527fcfdb9256a3d90cc6d479617ca43d8c8d264a9f5fe7f480029c4d918862c46db490602001610f4a565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612410575060025473ffffffffffffffffffffffffffffffffffffffff1633145b612476576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b601c546301000000900460ff161561249357612493600b54613551565b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8416908117909155601e829055604080517f748fc63b000000000000000000000000000000000000000000000000000000008152905163748fc63b9160048082019260209290919082900301816000875af1158015612531573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125559190614233565b61255f90826141be565b601d555050565b600080600080612574613800565b9150600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633c09868e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156125e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126079190614233565b92506000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612678573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061269c9190614233565b9050838311156126fa57670de0b6b3a7640000816126ba868661421c565b6126c49190614181565b6126ce91906141be565b945082620f42406126df868361421c565b6126e99190614181565b6126f391906141be565b9150612774565b670de0b6b3a76400008161270e858761421c565b6127189190614181565b61272291906141be565b61274c907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff614459565b945082620f424061275d828761421c565b6127679190614181565b61277191906141be565b91505b5090919293565b60005473ffffffffffffffffffffffffffffffffffffffff163314806127b8575060025473ffffffffffffffffffffffffffffffffffffffff1633145b61281e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b601891909155601955565b60008054819073ffffffffffffffffffffffffffffffffffffffff16331480612869575060025473ffffffffffffffffffffffffffffffffffffffff1633145b6128cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b6000851180156128df5750600084115b15612946576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f43616e206f6e6c792073656c6c20696e206f6e6520646972656374696f6e00006044820152606401610a48565b601c546301000000900460ff16156129e657600554600b546040517f1f4f5b4200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921691631f4f5b42916129b39160040190815260200190565b600060405180830381600087803b1580156129cd57600080fd5b505af11580156129e1573d6000803e3d6000fd5b505050505b60006129f0612566565b9350505050601954811115612a61576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5065672062616e64205b5457414d4d5d000000000000000000000000000000006044820152606401610a48565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166378dd02986040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ace573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612af29190614233565b600b558415612dee5784915060008211612b68576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f46504920736f6c64206d757374206265206e6f6e7a65726f00000000000000006044820152606401610a48565b601b54821115612bd4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f546f6f206d7563682046504920736f6c640000000000000000000000000000006044820152606401610a48565b6003546040517f6a257ebc0000000000000000000000000000000000000000000000000000000081523060048201526024810184905273ffffffffffffffffffffffffffffffffffffffff90911690636a257ebc90604401600060405180830381600087803b158015612c4657600080fd5b505af1158015612c5a573d6000803e3d6000fd5b50506003546005546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152602481018790529116925063095ea7b391506044016020604051808303816000875af1158015612cd9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cfd9190614515565b50601c5462010000900460ff1615612dc25760055473ffffffffffffffffffffffffffffffffffffffff166381ca79988386612d3b57601d54612d3d565b865b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925260248201526044016020604051808303816000875af1158015612d98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dbc9190614233565b50613055565b60055473ffffffffffffffffffffffffffffffffffffffff1663c9738a0d8386612d3b57601d54612d3d565b85925060008311612e5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4652415820736f6c64206d757374206265206e6f6e7a65726f000000000000006044820152606401610a48565b601a54831115612ec7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f546f6f206d756368204652415820736f6c6400000000000000000000000000006044820152606401610a48565b600480546005546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182169381019390935260248301869052169063095ea7b3906044016020604051808303816000875af1158015612f44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f689190614515565b50601c5462010000900460ff1615612fa65760055473ffffffffffffffffffffffffffffffffffffffff1663c9738a0d8486612d3b57601d54612d3d565b60055473ffffffffffffffffffffffffffffffffffffffff166381ca79988486612fd257601d54612fd4565b865b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925260248201526044016020604051808303816000875af115801561302f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130539190614233565b505b601c80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff166301000000179055600b54604080519182526020820185905281018390524260608201527fc26bbc8178bf327125d683aff5eff4547698645ff5efff7b616fe3fac345637a9060800160405180910390a150935093915050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480613112575060025473ffffffffffffffffffffffffffffffffffffffff1633145b613178576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b73ffffffffffffffffffffffffffffffffffffffff81166131f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f5a65726f206164647265737320646574656374656400000000000000000000006044820152606401610a48565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d602052604090205460ff1615613285576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4164647265737320616c726561647920657869737473000000000000000000006044820152606401610a48565b73ffffffffffffffffffffffffffffffffffffffff81166000818152600d6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155600c805491820181559093527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c790920180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905590519182527faa5bd6bda335b0c74f281b4b10d444ed06cd74963d7d77daa9a274eb4a7b36399101610f4a565b60008060008061336c613800565b9050600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633c09868e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156133db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133ff9190614233565b9350838111156134335780620f4240613418868361421c565b6134229190614181565b61342c91906141be565b9250613459565b80620f4240613442828761421c565b61344c9190614181565b61345691906141be565b92505b601854831115915050909192565b60005473ffffffffffffffffffffffffffffffffffffffff163314806134a4575060025473ffffffffffffffffffffffffffffffffffffffff1633145b61350a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60005473ffffffffffffffffffffffffffffffffffffffff1633148061358e575060025473ffffffffffffffffffffffffffffffffffffffff1633145b6135f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b60055473ffffffffffffffffffffffffffffffffffffffff16631f4f5b42821561361e5782613622565b600b545b6040518263ffffffff1660e01b815260040161364091815260200190565b600060405180830381600087803b15801561365a57600080fd5b505af115801561366e573d6000803e3d6000fd5b5050601c80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff169055505050565b60006136a98383610f55565b6003549091506136d19073ffffffffffffffffffffffffffffffffffffffff16333086613b00565b6004546136f59073ffffffffffffffffffffffffffffffffffffffff163383613c96565b60408051848152602081018390527fa7c2e65a1acb60d7ad1de1c523988ccedba739d1184defb9c84afaeb6479b2619101611572565b60005473ffffffffffffffffffffffffffffffffffffffff16331480613768575060025473ffffffffffffffffffffffffffffffffffffffff1633145b6137ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b601c80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b6000806000806000600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613875573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138999190613fd4565b945094505093509350600083121580156138b257508115155b80156138d657508369ffffffffffffffffffff168169ffffffffffffffffffff1610155b61393c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c696420636861696e6c696e6b2070726963650000000000000000006044820152606401610a48565b600954610bef90600a614175565b60115460009060ff161561395f575060125490565b60009050620f4240601354826119629190614181565b60005473ffffffffffffffffffffffffffffffffffffffff163314806139b2575060025473ffffffffffffffffffffffffffffffffffffffff1633145b613a18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b601a91909155601b55565b60005473ffffffffffffffffffffffffffffffffffffffff16331480613a60575060025473ffffffffffffffffffffffffffffffffffffffff1633145b613ac6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b601c80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff81166101009182900460ff1615909102179055565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790529151600092839290881691613b9f9190614532565b6000604051808303816000865af19150503d8060008114613bdc576040519150601f19603f3d011682016040523d82523d6000602084013e613be1565b606091505b5091509150818015613c0b575080511580613c0b575080806020019051810190613c0b9190614515565b611dca576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f464160448201527f494c4544000000000000000000000000000000000000000000000000000000006064820152608401610a48565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790529151600092839290871691613d2d9190614532565b6000604051808303816000865af19150503d8060008114613d6a576040519150601f19603f3d011682016040523d82523d6000602084013e613d6f565b606091505b5091509150818015613d99575080511580613d99575080806020019051810190613d999190614515565b613dff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610a48565b5050505050565b8015158114613e1457600080fd5b50565b60008060008060008060c08789031215613e3057600080fd5b8635613e3b81613e06565b955060208701359450604087013593506060870135613e5981613e06565b9598949750929560808101359460a0909101359350915050565b73ffffffffffffffffffffffffffffffffffffffff81168114613e1457600080fd5b600080600060608486031215613eaa57600080fd5b8335613eb581613e73565b92506020840135613ec581613e73565b91506040840135613ed581613e73565b809150509250925092565b600060208284031215613ef257600080fd5b8135613efd81613e73565b9392505050565b60008060408385031215613f1757600080fd5b50508035926020909101359150565b600060208284031215613f3857600080fd5b5035919050565b60008060408385031215613f5257600080fd5b8235613f5d81613e73565b946020939093013593505050565b60008060408385031215613f7e57600080fd5b8235613f5d81613e06565b600080600060608486031215613f9e57600080fd5b505081359360208301359350604090920135919050565b805169ffffffffffffffffffff81168114613fcf57600080fd5b919050565b600080600080600060a08688031215613fec57600080fd5b613ff586613fb5565b945060208601519350604086015192506060860151915061401860808701613fb5565b90509295509295909350565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600181815b808511156140ac57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561409257614092614024565b8085161561409f57918102915b93841c9390800290614058565b509250929050565b6000826140c35750600161416f565b816140d05750600061416f565b81600181146140e657600281146140f05761410c565b600191505061416f565b60ff84111561410157614101614024565b50506001821b61416f565b5060208310610133831016604e8410600b841016171561412f575081810a61416f565b6141398383614053565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561416b5761416b614024565b0290505b92915050565b6000613efd83836140b4565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156141b9576141b9614024565b500290565b6000826141f4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60006020828403121561420b57600080fd5b815160ff81168114613efd57600080fd5b60008282101561422e5761422e614024565b500390565b60006020828403121561424557600080fd5b5051919050565b6000821982111561425f5761425f614024565b500190565b6000808312837f80000000000000000000000000000000000000000000000000000000000000000183128115161561429e5761429e614024565b837f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0183138116156142d2576142d2614024565b50500390565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0384138115161561431257614312614024565b827f800000000000000000000000000000000000000000000000000000000000000003841281161561434657614346614024565b50500190565b80516dffffffffffffffffffffffffffff81168114613fcf57600080fd5b60008060006060848603121561437f57600080fd5b6143888461434c565b92506143966020850161434c565b9150604084015163ffffffff81168114613ed557600080fd5b6000806000606084860312156143c457600080fd5b83516143cf81613e06565b60208501519093506143e081613e73565b80925050604084015190509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361445257614452614024565b5060010190565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60008413600084138583048511828216161561449a5761449a614024565b7f800000000000000000000000000000000000000000000000000000000000000060008712868205881281841616156144d5576144d5614024565b600087129250878205871284841616156144f1576144f1614024565b8785058712818416161561450757614507614024565b505050929093029392505050565b60006020828403121561452757600080fd5b8151613efd81613e06565b6000825160005b818110156145535760208186018101518583015201614539565b81811115614562576000828501525b50919091019291505056fea2646970667358221220208fed16333a2046b1f9866232ee4988528031799d47c7654db9f03ac633a27964736f6c634300080d003300000000000000000000000026ce2091749059a66703cd4b998156d94ec393ef0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000853d955acef822db058eb8505911ed77f175b99e0000000000000000000000005ca135cb8527d76e932f34b5145575f9d8cbe08e0000000000000000000000007d95b33cbec441917d4f617482d4b5c7e6c35902000000000000000000000000b9e1e3a9feff48998e45fa90847ed4d467e8bcfd00000000000000000000000059985d79e1e69f659f4ab97db07a35ce73d9174b0000000000000000000000007086f2acb5558043ff9ce3df346d8e3fb4f4f452
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106104715760003560e01c80638980f11f11610250578063ba92341e11610150578063d9ebcc2f116100c8578063e63a391f11610097578063ea36648a1161007c578063ea36648a14610964578063eb99aff814610981578063ef71c765146109a157600080fd5b8063e63a391f14610964578063e8d5931d1461096e57600080fd5b8063d9ebcc2f14610927578063da610fcf1461092f578063dc6663c714610937578063e24ab97b1461095757600080fd5b8063bf6a89a21161011f578063c70b6ad111610104578063c70b6ad11461090d578063cd080fbd14610915578063d578660a1461091e57600080fd5b8063bf6a89a2146108e7578063c5a36df1146108fa57600080fd5b8063ba92341e1461086c578063bc3d5a8e1461088c578063bda767ab146108b1578063bdacb303146108d457600080fd5b8063a2b2d0e9116101e3578063a7c027da116101b2578063b0e4556f11610197578063b0e4556f1461083a578063b565c0cb1461085a578063b5d7684b1461086357600080fd5b8063a7c027da1461081a578063ac12d5971461082d57600080fd5b8063a2b2d0e9146107ac578063a42b4b25146107d4578063a4c3e73c146107e7578063a63b39e91461080757600080fd5b80639238c0ac1161021f5780639238c0ac1461077857806395082d25146107815780639c97ca1b146107905780639fc397e3146107a357600080fd5b80638980f11f146107295780638da5cb5b1461073c57806390f749c71461075c578063919e06ce1461076557600080fd5b806350fc60cb11610376578063694033f2116102ee57806382cd8713116102bd57806386c8c345116102a257806386c8c345146106e3578063882c95c1146106f657806388b93d9a1461071657600080fd5b806382cd8713146106b75780638583f21c146106da57600080fd5b8063694033f2146106955780636e7813ff1461069e57806379ba5097146106a657806379df3933146106ae57600080fd5b80636195e1f11161034557806365525bf61161032a57806365525bf61461066557806367694bae146106795780636830f5711461068257600080fd5b80636195e1f114610653578063631a5a171461065c57600080fd5b806350fc60cb146105ed57806353a47bb7146106005780635592e9f514610620578063608984611461064057600080fd5b80632f7e992f116104095780633ae2e4a3116103d85780634608fd46116103bd5780634608fd46146105ba57806349696b20146105c75780634d6f9ef2146105da57600080fd5b80633ae2e4a3146105945780634070a0c9146105a757600080fd5b80632f7e992f1461056757806330fd8a461461057057806335f77feb146105825780633a0319d71461058b57600080fd5b80631627540c116104455780631627540c146104dc5780631937bdf9146104ef5780631eaa95321461050f5780632141203e1461052257600080fd5b8062aa08fd1461047657806309761c7e1461048b57806309d32681146104a6578063152129b2146104b9575b600080fd5b610489610484366004613e17565b6109a9565b005b610493610aa5565b6040519081526020015b60405180910390f35b6104896104b4366004613e95565b610c14565b601c546104cc9062010000900460ff1681565b604051901515815260200161049d565b6104896104ea366004613ee0565b610e34565b6104936104fd366004613ee0565b600e6020526000908152604090205481565b61049361051d366004613f04565b610f55565b6007546105429073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161049d565b61049360155481565b601c546104cc90610100900460ff1681565b610493601b5481565b610493601a5481565b6104936105a2366004613f04565b6110fe565b6104896105b5366004613f26565b6113a2565b6011546104cc9060ff1681565b6105426105d5366004613f26565b61144a565b6104936105e8366004613f04565b611481565b6104896105fb366004613f26565b611580565b6001546105429073ffffffffffffffffffffffffffffffffffffffff1681565b600a546105429073ffffffffffffffffffffffffffffffffffffffff1681565b61048961064e366004613f26565b611628565b61049360125481565b61049360135481565b601c546104cc906301000000900460ff1681565b61049360195481565b610489610690366004613f3f565b61170a565b61049360185481565b610493611937565b610489611971565b61049360085481565b6106bf611abc565b6040805193845260208401929092529082015260600161049d565b610493601e5481565b6104896106f1366004613f6b565b611c3b565b6003546105429073ffffffffffffffffffffffffffffffffffffffff1681565b610489610724366004613f26565b611e2d565b610489610737366004613f3f565b611fa2565b6000546105429073ffffffffffffffffffffffffffffffffffffffff1681565b61049360165481565b610489610773366004613ee0565b6120bd565b610493601d5481565b610493670de0b6b3a764000081565b61048961079e366004613f3f565b6123d3565b610493600f5481565b6107b4612566565b60408051948552602085019390935291830152606082015260800161049d565b6104896107e2366004613f04565b61277b565b670de0b6b3a7640000805b6040805192835260208301919091520161049d565b6107f2610815366004613f89565b612829565b610489610828366004613ee0565b6130d5565b6014546104cc9060ff1681565b6004546105429073ffffffffffffffffffffffffffffffffffffffff1681565b61049360095481565b61049360105481565b6005546105429073ffffffffffffffffffffffffffffffffffffffff1681565b61089461335e565b60408051938452602084019290925215159082015260600161049d565b6104cc6108bf366004613ee0565b600d6020526000908152604090205460ff1681565b6104896108e2366004613ee0565b613467565b6104896108f5366004613f26565b613551565b610493610908366004613f04565b61369d565b61048961372b565b610493600b5481565b61049360175481565b610493613800565b61049361394a565b6002546105429073ffffffffffffffffffffffffffffffffffffffff1681565b601c546104cc9060ff1681565b610493620f424081565b61048961097c366004613f04565b613975565b6006546105429073ffffffffffffffffffffffffffffffffffffffff1681565b610489613a23565b60005473ffffffffffffffffffffffffffffffffffffffff163314806109e6575060025473ffffffffffffffffffffffffffffffffffffffff1633145b610a51576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b000000000000000000000060448201526064015b60405180910390fd5b601180549615157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00978816179055601294909455601392909255601480549115159190941617909255601591909155601655565b6000806000806000600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015610b1a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b3e9190613fd4565b94509450509350935060008312158015610b5757508115155b8015610b7b57508369ffffffffffffffffffff168169ffffffffffffffffffff1610155b610be1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c696420636861696e6c696e6b2070726963650000000000000000006044820152606401610a48565b600854610bef90600a614175565b610c0184670de0b6b3a7640000614181565b610c0b91906141be565b94505050505090565b60005473ffffffffffffffffffffffffffffffffffffffff16331480610c51575060025473ffffffffffffffffffffffffffffffffffffffff1633145b610cb7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b6006805473ffffffffffffffffffffffffffffffffffffffff8086167fffffffffffffffffffffffff0000000000000000000000000000000000000000928316811790935560078054868316908416179055600a805491851691909216179055604080517f313ce567000000000000000000000000000000000000000000000000000000008152905163313ce567916004808201926020929091908290030181865afa158015610d6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d8f91906141f9565b60ff16600855600754604080517f313ce567000000000000000000000000000000000000000000000000000000008152905173ffffffffffffffffffffffffffffffffffffffff9092169163313ce567916004808201926020929091908290030181865afa158015610e05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e2991906141f9565b60ff16600955505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610edb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201527f6f726d207468697320616374696f6e00000000000000000000000000000000006064820152608401610a48565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22906020015b60405180910390a150565b601c54600090610100900460ff1615610fca576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f52656465656d73207061757365640000000000000000000000000000000000006044820152606401610a48565b600080610fd561335e565b925050915080611041576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f5065672062616e64205b52656465656d5d0000000000000000000000000000006044820152606401610a48565b670de0b6b3a76400006110548387614181565b61105e91906141be565b9250620f424061106c611937565b6110769085614181565b61108091906141be565b61108a908461421c565b9250838310156110f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f536c697070616765205b52656465656d5d0000000000000000000000000000006044820152606401610a48565b505092915050565b601c5460009060ff161561116e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f4d696e74732070617573656400000000000000000000000000000000000000006044820152606401610a48565b60008061117961335e565b9250509150806111e5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5065672062616e64205b4d696e745d00000000000000000000000000000000006044820152606401610a48565b816111f8670de0b6b3a764000087614181565b61120291906141be565b9250620f424061121061394a565b61121a9085614181565b61122491906141be565b61122e908461421c565b92508383101561129a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f536c697070616765205b4d696e745d00000000000000000000000000000000006044820152606401610a48565b601754600354604080517f18160ddd0000000000000000000000000000000000000000000000000000000081529051869273ffffffffffffffffffffffffffffffffffffffff16916318160ddd9160048083019260209291908290030181865afa15801561130c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113309190614233565b61133a919061424c565b11156110f6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f465049206d696e742063617000000000000000000000000000000000000000006044820152606401610a48565b60005473ffffffffffffffffffffffffffffffffffffffff163314806113df575060025473ffffffffffffffffffffffffffffffffffffffff1633145b611445576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b601755565b600c818154811061145a57600080fd5b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b600061148d83836110fe565b6004549091506114b59073ffffffffffffffffffffffffffffffffffffffff16333086613b00565b6003546040517f6a257ebc0000000000000000000000000000000000000000000000000000000081523360048201526024810183905273ffffffffffffffffffffffffffffffffffffffff90911690636a257ebc90604401600060405180830381600087803b15801561152757600080fd5b505af115801561153b573d6000803e3d6000fd5b505060408051868152602081018590527ff4c708dad0640bb97b06e573b39b194c40301c581997805cbc86390ace5848c793500190505b60405180910390a192915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314806115bd575060025473ffffffffffffffffffffffffffffffffffffffff1633145b611623576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b601055565b336000818152600d602052604090205460ff166116a1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f496e76616c696420414d4f0000000000000000000000000000000000000000006044820152606401610a48565b60045482906116c89073ffffffffffffffffffffffffffffffffffffffff16333084613b00565b336000908152600e6020526040812080548392906116e7908490614264565b9250508190555080600f60008282546117009190614264565b9091555050505050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611747575060025473ffffffffffffffffffffffffffffffffffffffff1633145b6117ad576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600d6020526040902054829060ff1661183e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f496e76616c696420414d4f0000000000000000000000000000000000000000006044820152606401610a48565b601054600f548391906118529083906142d8565b13156118ba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f426f72726f7720636170000000000000000000000000000000000000000000006044820152606401610a48565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600e6020526040812080548392906118ef9084906142d8565b9250508190555080600f600082825461190891906142d8565b90915550506004546119319073ffffffffffffffffffffffffffffffffffffffff168585613c96565b50505050565b60145460009060ff161561194c575060155490565b60009050620f4240601654826119629190614181565b61196c91906141be565b905090565b60015473ffffffffffffffffffffffffffffffffffffffff163314611a18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527f2063616e20616363657074206f776e65727368697000000000000000000000006064820152608401610a48565b6000546001546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160018054600080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b6005546040517f2e0ae3750000000000000000000000000000000000000000000000000000000081524260048201526000918291829173ffffffffffffffffffffffffffffffffffffffff1690632e0ae37590602401600060405180830381600087803b158015611b2c57600080fd5b505af1158015611b40573d6000803e3d6000fd5b50505050600080600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015611bb4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd8919061436a565b50601c546dffffffffffffffffffffffffffff92831694509116915062010000900460ff1615611c0d57819450809350611c14565b8094508193505b50829050611c2a84670de0b6b3a7640000614181565b611c3491906141be565b9050909192565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611c78575060025473ffffffffffffffffffffffffffffffffffffffff1633145b611cde576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b8115611dd2576003546040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906342966c689082906370a0823190602401602060405180830381865afa158015611d5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d7e9190614233565b6040518263ffffffff1660e01b8152600401611d9c91815260200190565b600060405180830381600087803b158015611db657600080fd5b505af1158015611dca573d6000803e3d6000fd5b505050505050565b6003546040517f42966c680000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff909116906342966c6890602401611d9c565b5050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611e6a575060025473ffffffffffffffffffffffffffffffffffffffff1633145b611ed0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b60055460009073ffffffffffffffffffffffffffffffffffffffff166381fd0a468315611efd5783611f01565b600b545b6040518263ffffffff1660e01b8152600401611f1f91815260200190565b6060604051808303816000875af1158015611f3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f6291906143af565b50509050808015611f71575081155b15611e2957601c80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff1690555050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480611fdf575060025473ffffffffffffffffffffffffffffffffffffffff1633145b612045576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b60005461206a90839073ffffffffffffffffffffffffffffffffffffffff1683613c96565b6040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527f55350610fe57096d8c0ffa30beede987326bccfcb0b4415804164d0dd50ce8b1910160405180910390a15050565b60005473ffffffffffffffffffffffffffffffffffffffff163314806120fa575060025473ffffffffffffffffffffffffffffffffffffffff1633145b612160576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b73ffffffffffffffffffffffffffffffffffffffff81166121dd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f5a65726f206164647265737320646574656374656400000000000000000000006044820152606401610a48565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d602052604090205460ff161515600114612271576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f41646472657373206e6f6e6578697374616e74000000000000000000000000006044820152606401610a48565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d6020526040812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690555b600c5481101561238c578173ffffffffffffffffffffffffffffffffffffffff16600c82815481106122f1576122f16143f2565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff160361237a576000600c828154811061232d5761232d6143f2565b9060005260206000200160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061238c565b8061238481614421565b9150506122bd565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527fcfdb9256a3d90cc6d479617ca43d8c8d264a9f5fe7f480029c4d918862c46db490602001610f4a565b60005473ffffffffffffffffffffffffffffffffffffffff16331480612410575060025473ffffffffffffffffffffffffffffffffffffffff1633145b612476576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b601c546301000000900460ff161561249357612493600b54613551565b600580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8416908117909155601e829055604080517f748fc63b000000000000000000000000000000000000000000000000000000008152905163748fc63b9160048082019260209290919082900301816000875af1158015612531573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125559190614233565b61255f90826141be565b601d555050565b600080600080612574613800565b9150600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633c09868e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156125e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126079190614233565b92506000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612678573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061269c9190614233565b9050838311156126fa57670de0b6b3a7640000816126ba868661421c565b6126c49190614181565b6126ce91906141be565b945082620f42406126df868361421c565b6126e99190614181565b6126f391906141be565b9150612774565b670de0b6b3a76400008161270e858761421c565b6127189190614181565b61272291906141be565b61274c907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff614459565b945082620f424061275d828761421c565b6127679190614181565b61277191906141be565b91505b5090919293565b60005473ffffffffffffffffffffffffffffffffffffffff163314806127b8575060025473ffffffffffffffffffffffffffffffffffffffff1633145b61281e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b601891909155601955565b60008054819073ffffffffffffffffffffffffffffffffffffffff16331480612869575060025473ffffffffffffffffffffffffffffffffffffffff1633145b6128cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b6000851180156128df5750600084115b15612946576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f43616e206f6e6c792073656c6c20696e206f6e6520646972656374696f6e00006044820152606401610a48565b601c546301000000900460ff16156129e657600554600b546040517f1f4f5b4200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff90921691631f4f5b42916129b39160040190815260200190565b600060405180830381600087803b1580156129cd57600080fd5b505af11580156129e1573d6000803e3d6000fd5b505050505b60006129f0612566565b9350505050601954811115612a61576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f5065672062616e64205b5457414d4d5d000000000000000000000000000000006044820152606401610a48565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166378dd02986040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ace573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612af29190614233565b600b558415612dee5784915060008211612b68576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f46504920736f6c64206d757374206265206e6f6e7a65726f00000000000000006044820152606401610a48565b601b54821115612bd4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f546f6f206d7563682046504920736f6c640000000000000000000000000000006044820152606401610a48565b6003546040517f6a257ebc0000000000000000000000000000000000000000000000000000000081523060048201526024810184905273ffffffffffffffffffffffffffffffffffffffff90911690636a257ebc90604401600060405180830381600087803b158015612c4657600080fd5b505af1158015612c5a573d6000803e3d6000fd5b50506003546005546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152602481018790529116925063095ea7b391506044016020604051808303816000875af1158015612cd9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cfd9190614515565b50601c5462010000900460ff1615612dc25760055473ffffffffffffffffffffffffffffffffffffffff166381ca79988386612d3b57601d54612d3d565b865b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925260248201526044016020604051808303816000875af1158015612d98573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dbc9190614233565b50613055565b60055473ffffffffffffffffffffffffffffffffffffffff1663c9738a0d8386612d3b57601d54612d3d565b85925060008311612e5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f4652415820736f6c64206d757374206265206e6f6e7a65726f000000000000006044820152606401610a48565b601a54831115612ec7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f546f6f206d756368204652415820736f6c6400000000000000000000000000006044820152606401610a48565b600480546005546040517f095ea7b300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182169381019390935260248301869052169063095ea7b3906044016020604051808303816000875af1158015612f44573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f689190614515565b50601c5462010000900460ff1615612fa65760055473ffffffffffffffffffffffffffffffffffffffff1663c9738a0d8486612d3b57601d54612d3d565b60055473ffffffffffffffffffffffffffffffffffffffff166381ca79988486612fd257601d54612fd4565b865b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b168152600481019290925260248201526044016020604051808303816000875af115801561302f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130539190614233565b505b601c80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff166301000000179055600b54604080519182526020820185905281018390524260608201527fc26bbc8178bf327125d683aff5eff4547698645ff5efff7b616fe3fac345637a9060800160405180910390a150935093915050565b60005473ffffffffffffffffffffffffffffffffffffffff16331480613112575060025473ffffffffffffffffffffffffffffffffffffffff1633145b613178576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b73ffffffffffffffffffffffffffffffffffffffff81166131f5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f5a65726f206164647265737320646574656374656400000000000000000000006044820152606401610a48565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600d602052604090205460ff1615613285576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4164647265737320616c726561647920657869737473000000000000000000006044820152606401610a48565b73ffffffffffffffffffffffffffffffffffffffff81166000818152600d6020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155600c805491820181559093527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c790920180547fffffffffffffffffffffffff0000000000000000000000000000000000000000168417905590519182527faa5bd6bda335b0c74f281b4b10d444ed06cd74963d7d77daa9a274eb4a7b36399101610f4a565b60008060008061336c613800565b9050600a60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633c09868e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156133db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133ff9190614233565b9350838111156134335780620f4240613418868361421c565b6134229190614181565b61342c91906141be565b9250613459565b80620f4240613442828761421c565b61344c9190614181565b61345691906141be565b92505b601854831115915050909192565b60005473ffffffffffffffffffffffffffffffffffffffff163314806134a4575060025473ffffffffffffffffffffffffffffffffffffffff1633145b61350a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60005473ffffffffffffffffffffffffffffffffffffffff1633148061358e575060025473ffffffffffffffffffffffffffffffffffffffff1633145b6135f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b60055473ffffffffffffffffffffffffffffffffffffffff16631f4f5b42821561361e5782613622565b600b545b6040518263ffffffff1660e01b815260040161364091815260200190565b600060405180830381600087803b15801561365a57600080fd5b505af115801561366e573d6000803e3d6000fd5b5050601c80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffff169055505050565b60006136a98383610f55565b6003549091506136d19073ffffffffffffffffffffffffffffffffffffffff16333086613b00565b6004546136f59073ffffffffffffffffffffffffffffffffffffffff163383613c96565b60408051848152602081018390527fa7c2e65a1acb60d7ad1de1c523988ccedba739d1184defb9c84afaeb6479b2619101611572565b60005473ffffffffffffffffffffffffffffffffffffffff16331480613768575060025473ffffffffffffffffffffffffffffffffffffffff1633145b6137ce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b601c80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00811660ff90911615179055565b6000806000806000600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613875573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138999190613fd4565b945094505093509350600083121580156138b257508115155b80156138d657508369ffffffffffffffffffff168169ffffffffffffffffffff1610155b61393c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f496e76616c696420636861696e6c696e6b2070726963650000000000000000006044820152606401610a48565b600954610bef90600a614175565b60115460009060ff161561395f575060125490565b60009050620f4240601354826119629190614181565b60005473ffffffffffffffffffffffffffffffffffffffff163314806139b2575060025473ffffffffffffffffffffffffffffffffffffffff1633145b613a18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b601a91909155601b55565b60005473ffffffffffffffffffffffffffffffffffffffff16331480613a60575060025473ffffffffffffffffffffffffffffffffffffffff1633145b613ac6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f74206f776e6572206f722074696d656c6f636b00000000000000000000006044820152606401610a48565b601c80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff81166101009182900460ff1615909102179055565b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd000000000000000000000000000000000000000000000000000000001790529151600092839290881691613b9f9190614532565b6000604051808303816000865af19150503d8060008114613bdc576040519150601f19603f3d011682016040523d82523d6000602084013e613be1565b606091505b5091509150818015613c0b575080511580613c0b575080806020019051810190613c0b9190614515565b611dca576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f5472616e7366657248656c7065723a205452414e534645525f46524f4d5f464160448201527f494c4544000000000000000000000000000000000000000000000000000000006064820152608401610a48565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001790529151600092839290871691613d2d9190614532565b6000604051808303816000865af19150503d8060008114613d6a576040519150601f19603f3d011682016040523d82523d6000602084013e613d6f565b606091505b5091509150818015613d99575080511580613d99575080806020019051810190613d999190614515565b613dff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5472616e7366657248656c7065723a205452414e534645525f4641494c4544006044820152606401610a48565b5050505050565b8015158114613e1457600080fd5b50565b60008060008060008060c08789031215613e3057600080fd5b8635613e3b81613e06565b955060208701359450604087013593506060870135613e5981613e06565b9598949750929560808101359460a0909101359350915050565b73ffffffffffffffffffffffffffffffffffffffff81168114613e1457600080fd5b600080600060608486031215613eaa57600080fd5b8335613eb581613e73565b92506020840135613ec581613e73565b91506040840135613ed581613e73565b809150509250925092565b600060208284031215613ef257600080fd5b8135613efd81613e73565b9392505050565b60008060408385031215613f1757600080fd5b50508035926020909101359150565b600060208284031215613f3857600080fd5b5035919050565b60008060408385031215613f5257600080fd5b8235613f5d81613e73565b946020939093013593505050565b60008060408385031215613f7e57600080fd5b8235613f5d81613e06565b600080600060608486031215613f9e57600080fd5b505081359360208301359350604090920135919050565b805169ffffffffffffffffffff81168114613fcf57600080fd5b919050565b600080600080600060a08688031215613fec57600080fd5b613ff586613fb5565b945060208601519350604086015192506060860151915061401860808701613fb5565b90509295509295909350565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600181815b808511156140ac57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561409257614092614024565b8085161561409f57918102915b93841c9390800290614058565b509250929050565b6000826140c35750600161416f565b816140d05750600061416f565b81600181146140e657600281146140f05761410c565b600191505061416f565b60ff84111561410157614101614024565b50506001821b61416f565b5060208310610133831016604e8410600b841016171561412f575081810a61416f565b6141398383614053565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561416b5761416b614024565b0290505b92915050565b6000613efd83836140b4565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156141b9576141b9614024565b500290565b6000826141f4577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60006020828403121561420b57600080fd5b815160ff81168114613efd57600080fd5b60008282101561422e5761422e614024565b500390565b60006020828403121561424557600080fd5b5051919050565b6000821982111561425f5761425f614024565b500190565b6000808312837f80000000000000000000000000000000000000000000000000000000000000000183128115161561429e5761429e614024565b837f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0183138116156142d2576142d2614024565b50500390565b6000808212827f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0384138115161561431257614312614024565b827f800000000000000000000000000000000000000000000000000000000000000003841281161561434657614346614024565b50500190565b80516dffffffffffffffffffffffffffff81168114613fcf57600080fd5b60008060006060848603121561437f57600080fd5b6143888461434c565b92506143966020850161434c565b9150604084015163ffffffff81168114613ed557600080fd5b6000806000606084860312156143c457600080fd5b83516143cf81613e06565b60208501519093506143e081613e73565b80925050604084015190509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361445257614452614024565b5060010190565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60008413600084138583048511828216161561449a5761449a614024565b7f800000000000000000000000000000000000000000000000000000000000000060008712868205881281841616156144d5576144d5614024565b600087129250878205871284841616156144f1576144f1614024565b8785058712818416161561450757614507614024565b505050929093029392505050565b60006020828403121561452757600080fd5b8151613efd81613e06565b6000825160005b818110156145535760208186018101518583015201614539565b81811115614562576000828501525b50919091019291505056fea2646970667358221220208fed16333a2046b1f9866232ee4988528031799d47c7654db9f03ac633a27964736f6c634300080d0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000026ce2091749059a66703cd4b998156d94ec393ef0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000853d955acef822db058eb8505911ed77f175b99e0000000000000000000000005ca135cb8527d76e932f34b5145575f9d8cbe08e0000000000000000000000007d95b33cbec441917d4f617482d4b5c7e6c35902000000000000000000000000b9e1e3a9feff48998e45fa90847ed4d467e8bcfd00000000000000000000000059985d79e1e69f659f4ab97db07a35ce73d9174b0000000000000000000000007086f2acb5558043ff9ce3df346d8e3fb4f4f452
-----Decoded View---------------
Arg [0] : _creator_address (address): 0x26Ce2091749059a66703CD4B998156d94eC393ef
Arg [1] : _timelock_address (address): 0x0000000000000000000000000000000000000000
Arg [2] : _address_pack (address[6]): 0x853d955aCEf822Db058eb8505911ED77F175b99e,0x5Ca135cB8527d76e932f34B5145575F9d8cbE08E,0x7d95b33cbEC441917d4f617482d4b5c7e6c35902,0xB9E1E3A9feFf48998E45Fa90847ed4D467E8BcfD,0x59985D79E1e69f659f4aB97Db07A35cE73D9174B,0x7086F2aCB5558043fF9cE3df346D8E3FB4F4f452
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 00000000000000000000000026ce2091749059a66703cd4b998156d94ec393ef
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [2] : 000000000000000000000000853d955acef822db058eb8505911ed77f175b99e
Arg [3] : 0000000000000000000000005ca135cb8527d76e932f34b5145575f9d8cbe08e
Arg [4] : 0000000000000000000000007d95b33cbec441917d4f617482d4b5c7e6c35902
Arg [5] : 000000000000000000000000b9e1e3a9feff48998e45fa90847ed4d467e8bcfd
Arg [6] : 00000000000000000000000059985d79e1e69f659f4ab97db07a35ce73d9174b
Arg [7] : 0000000000000000000000007086f2acb5558043ff9ce3df346d8e3fb4f4f452
Deployed Bytecode Sourcemap
139818:21802:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;159809:607;;;;;;:::i;:::-;;:::i;:::-;;143925:372;;;:::i;:::-;;;939:25:1;;;927:2;912:18;143925:372:0;;;;;;;;158203:477;;;;;;:::i;:::-;;:::i;141885:26::-;;;;;;;;;;;;;;;1833:14:1;;1826:22;1808:41;;1796:2;1781:18;141885:26:0;1668:187:1;35902:141:0;;;;;;:::i;:::-;;:::i;140551:56::-;;;;;;:::i;:::-;;;;;;;;;;;;;;150145:800;;;;;;:::i;:::-;;:::i;140068:44::-;;;;;;;;;;;;2751:42:1;2739:55;;;2721:74;;2709:2;2694:18;140068:44:0;2545:256:1;141105:39:0;;;;;;141628:34;;;;;;;;;;;;141496:48;;;;;;141402:49;;;;;;148757:898;;;;;;:::i;:::-;;:::i;159476:112::-;;;;;;:::i;:::-;;:::i;140873:38::-;;;;;;;;;140393:27;;;;;;:::i;:::-;;:::i;149690:409::-;;;;;;:::i;:::-;;:::i;159342:126::-;;;;;;:::i;:::-;;:::i;35670:29::-;;;;;;;;;140216:34;;;;;;;;;156678:413;;;;;;:::i;:::-;;:::i;140918:37::-;;;;;;140968:44;;;;;;141918:39;;;;;;;;;;;;141350:38;;;;;;156060:552;;;;;;:::i;:::-;;:::i;141294:43::-;;;;;;146861:322;;;:::i;36051:271::-;;;:::i;140119:42::-;;;;;;144815:675;;;:::i;:::-;;;;4184:25:1;;;4240:2;4225:18;;4218:34;;;;4268:18;;;4261:34;4172:2;4157:18;144815:675:0;3982:319:1;142055:38:0;;;;;;155527:255;;;;;;:::i;:::-;;:::i;139914:18::-;;;;;;;;;154969:458;;;;;;:::i;:::-;;:::i;160920:300::-;;;;;;:::i;:::-;;:::i;35643:20::-;;;;;;;;;141157:46;;;;;;157530:665;;;;;;:::i;:::-;;:::i;141964:40::-;;;;;;141712:46;;141754:4;141712:46;;158688:440;;;;;;:::i;:::-;;:::i;140662:35::-;;;;;;147845:823;;;:::i;:::-;;;;5092:25:1;;;5148:2;5133:18;;5126:34;;;;5176:18;;;5169:34;5234:2;5219:18;;5212:34;5079:3;5064:19;147845:823:0;4863:389:1;159596:205:0;;;;;;:::i;:::-;;:::i;143632:255::-;143843:4;;143632:255;;;;5431:25:1;;;5487:2;5472:18;;5465:34;;;;5404:18;143632:255:0;5257:248:1;151479:3173:0;;;;;;:::i;:::-;;:::i;157176:323::-;;;;;;:::i;:::-;;:::i;141058:40::-;;;;;;;;;139939:17;;;;;;;;;140168:41;;;;;;140723:51;;;;;;139963:28;;;;;;;;;147234:554;;;:::i;:::-;;;;6527:25:1;;;6583:2;6568:18;;6561:34;;;;6638:14;6631:22;6611:18;;;6604:50;6515:2;6500:18;147234:554:0;6331:329:1;140427:36:0;;;;;;:::i;:::-;;;;;;;;;;;;;;;;160658:133;;;;;;:::i;:::-;;:::i;154660:301::-;;;;;;:::i;:::-;;:::i;150981:443::-;;;;;;:::i;:::-;;:::i;159136:92::-;;;:::i;140276:34::-;;;;;;141237:42;;;;;;144339:369;;;:::i;146537:302::-;;;:::i;139876:31::-;;;;;;;;;141589:32;;;;;;;;;141765:43;;141805:3;141765:43;;160424:226;;;;;;:::i;:::-;;:::i;140016:45::-;;;;;;;;;159236:98;;;:::i;159809:607::-;142214:5;;;;142200:10;:19;;:53;;-1:-1:-1;142237:16:0;;;;142223:10;:30;142200:53;142192:87;;;;;;;6867:2:1;142192:87:0;;;6849:21:1;6906:2;6886:18;;;6879:30;6945:23;6925:18;;;6918:51;6986:18;;142192:87:0;;;;;;;;;160105:19:::1;:42:::0;;;::::1;;::::0;;;::::1;;::::0;;160158:15:::1;:34:::0;;;;160203:19:::1;:42:::0;;;;160256:21:::1;:46:::0;;;::::1;;::::0;;;::::1;;::::0;;;160313:17:::1;:38:::0;;;;160362:21:::1;:46:::0;159809:607::o;143925:372::-;143973:7;143994:14;144010:9;144023:17;144042:22;144068:16;;;;;;;;;;;:32;;;:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;143993:109;;;;;;;;;144130:1;144121:5;:10;;:27;;;;-1:-1:-1;144135:13:0;;;144121:27;:57;;;;;144171:7;144152:26;;:15;:26;;;;144121:57;144113:93;;;;;;;7879:2:1;144113:93:0;;;7861:21:1;7918:2;7898:18;;;7891:30;7957:25;7937:18;;;7930:53;8000:18;;144113:93:0;7677:347:1;144113:93:0;144260:27;;144254:33;;:2;:33;:::i;:::-;144228:21;144236:5;144245:4;144228:21;:::i;:::-;144227:61;;;;:::i;:::-;144219:70;;;;;;143925:372;:::o;158203:477::-;142214:5;;;;142200:10;:19;;:53;;-1:-1:-1;142237:16:0;;;;142223:10;:30;142200:53;142192:87;;;;;;;6867:2:1;142192:87:0;;;6849:21:1;6906:2;6886:18;;;6879:30;6945:23;6925:18;;;6918:51;6986:18;;142192:87:0;6665:345:1;142192:87:0;158320:16:::1;:54:::0;;::::1;::::0;;::::1;::::0;;;::::1;::::0;::::1;::::0;;;158385:15:::1;:52:::0;;;;::::1;::::0;;::::1;;::::0;;158448:10:::1;:42:::0;;;;::::1;::::0;;;::::1;;::::0;;158579:27:::1;::::0;;;;;;;:25:::1;::::0;:27:::1;::::0;;::::1;::::0;::::1;::::0;;;;;;;;;158320:54;158579:27:::1;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;158549:57;;:27;:57:::0;158646:15:::1;::::0;:26:::1;::::0;;;;;;;:15:::1;::::0;;::::1;::::0;:24:::1;::::0;:26:::1;::::0;;::::1;::::0;::::1;::::0;;;;;;;;;:15;:26:::1;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;158617:55;;:26;:55:::0;-1:-1:-1;;;158203:477:0:o;35902:141::-;36382:5;;;;36368:10;:19;36360:79;;;;;;;10704:2:1;36360:79:0;;;10686:21:1;10743:2;10723:18;;;10716:30;10782:34;10762:18;;;10755:62;10853:17;10833:18;;;10826:45;10888:19;;36360:79:0;10502:411:1;36360:79:0;35974:14:::1;:23:::0;;;::::1;;::::0;::::1;::::0;;::::1;::::0;;;36013:22:::1;::::0;2721:74:1;;;36013:22:0::1;::::0;2709:2:1;2694:18;36013:22:0::1;;;;;;;;35902:141:::0;:::o;150145:800::-;150265:14;;150227:16;;150265:14;;;;;150264:15;150256:42;;;;;;;11120:2:1;150256:42:0;;;11102:21:1;11159:2;11139:18;;;11132:30;11198:16;11178:18;;;11171:44;11232:18;;150256:42:0;10918:338:1;150256:42:0;150359:21;150384:17;150405;:15;:17::i;:::-;150358:64;;;;;150556:12;150548:42;;;;;;;11463:2:1;150548:42:0;;;11445:21:1;11502:2;11482:18;;;11475:30;11541:19;11521:18;;;11514:47;11578:18;;150548:42:0;11261:341:1;150548:42:0;141754:4;150690:22;150699:13;150690:6;:22;:::i;:::-;150689:42;;;;:::i;:::-;150678:53;;141805:3;150794:12;:10;:12::i;:::-;150783:23;;:8;:23;:::i;:::-;150782:41;;;;:::i;:::-;150770:53;;;;:::i;:::-;;;150903:12;150891:8;:24;;150883:54;;;;;;;11939:2:1;150883:54:0;;;11921:21:1;11978:2;11958:18;;;11951:30;12017:19;11997:18;;;11990:47;12054:18;;150883:54:0;11737:341:1;150883:54:0;150245:700;;150145:800;;;;:::o;148757:898::-;148874:12;;148837:15;;148874:12;;148873:13;148865:38;;;;;;;12285:2:1;148865:38:0;;;12267:21:1;12324:2;12304:18;;;12297:30;12363:14;12343:18;;;12336:42;12395:18;;148865:38:0;12083:336:1;148865:38:0;148964:21;148989:17;149010;:15;:17::i;:::-;148963:64;;;;;149161:12;149153:40;;;;;;;12626:2:1;149153:40:0;;;12608:21:1;12665:2;12645:18;;;12638:30;12704:17;12684:18;;;12677:45;12739:18;;149153:40:0;12424:339:1;149153:40:0;149321:13;149292:25;141754:4;149292:7;:25;:::i;:::-;149291:43;;;;:::i;:::-;149281:53;;141805:3;149395:10;:8;:10::i;:::-;149385:20;;:7;:20;:::i;:::-;149384:38;;;;:::i;:::-;149373:49;;;;:::i;:::-;;;149500:11;149489:7;:22;;149481:50;;;;;;;12970:2:1;149481:50:0;;;12952:21:1;13009:2;12989:18;;;12982:30;13048:17;13028:18;;;13021:45;13083:18;;149481:50:0;12768:339:1;149481:50:0;149618:12;;149583:7;;:21;;;;;;;;149607:7;;149583;;;:19;;:21;;;;;;;;;;;;;;:7;:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:31;;;;:::i;:::-;:47;;149575:72;;;;;;;13636:2:1;149575:72:0;;;13618:21:1;13675:2;13655:18;;;13648:30;13714:14;13694:18;;;13687:42;13746:18;;149575:72:0;13434:336:1;159476:112:0;142214:5;;;;142200:10;:19;;:53;;-1:-1:-1;142237:16:0;;;;142223:10;:30;142200:53;142192:87;;;;;;;6867:2:1;142192:87:0;;;6849:21:1;6906:2;6886:18;;;6879:30;6945:23;6925:18;;;6918:51;6986:18;;142192:87:0;6665:345:1;142192:87:0;159552:12:::1;:28:::0;159476:112::o;140393:27::-;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;140393:27:0;:::o;149690:409::-;149763:15;149801:33;149813:7;149822:11;149801;:33::i;:::-;149916:4;;149791:43;;-1:-1:-1;149876:82:0;;149916:4;;149923:10;149943:4;149950:7;149876:31;:82::i;:::-;150006:7;;:40;;;;;150026:10;150006:40;;;13949:74:1;14039:18;;;14032:34;;;150006:7:0;;;;;:19;;13922:18:1;;150006:40:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;150064:27:0;;;5431:25:1;;;5487:2;5472:18;;5465:34;;;150064:27:0;;-1:-1:-1;5404:18:1;;-1:-1:-1;150064:27:0;;;;;;;;149690:409;;;;:::o;159342:126::-;142214:5;;;;142200:10;:19;;:53;;-1:-1:-1;142237:16:0;;;;142223:10;:30;142200:53;142192:87;;;;;;;6867:2:1;142192:87:0;;;6849:21:1;6906:2;6886:18;;;6879:30;6945:23;6925:18;;;6918:51;6986:18;;142192:87:0;6665:345:1;142192:87:0;159426:15:::1;:34:::0;159342:126::o;156678:413::-;156745:10;142365:17;;;;:4;:17;;;;;;;;142357:41;;;;;;;14279:2:1;142357:41:0;;;14261:21:1;14318:2;14298:18;;;14291:30;14357:13;14337:18;;;14330:41;14388:18;;142357:41:0;14077:335:1;142357:41:0;156891:4:::1;::::0;156798:11;;156851:86:::1;::::0;156891:4:::1;;156898:10;156918:4;156798:11:::0;156851:31:::1;:86::i;:::-;157010:10;156987:34;::::0;;;:22:::1;:34;::::0;;;;:51;;157025:13;;156987:34;:51:::1;::::0;157025:13;;156987:51:::1;:::i;:::-;;;;;;;;157070:13;157049:17;;:34;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;;;;156678:413:0:o;156060:552::-;142214:5;;;;142200:10;:19;;:53;;-1:-1:-1;142237:16:0;;;;142223:10;:30;142200:53;142192:87;;;;;;;6867:2:1;142192:87:0;;;6849:21:1;6906:2;6886:18;;;6879:30;6945:23;6925:18;;;6918:51;6986:18;;142192:87:0;6665:345:1;142192:87:0;142365:17:::1;::::0;::::1;;::::0;;;:4:::1;:17;::::0;;;;;156160:15;;142365:17:::1;;142357:41;;;::::0;::::1;::::0;;14279:2:1;142357:41:0::1;::::0;::::1;14261:21:1::0;14318:2;14298:18;;;14291:30;14357:13;14337:18;;;14330:41;14388:18;;142357:41:0::1;14077:335:1::0;142357:41:0::1;156334:15:::2;::::0;156293:17:::2;::::0;156221:11;;156334:15;156293:36:::2;::::0;156221:11;;156293:36:::2;:::i;:::-;156292:57;;156284:80;;;::::0;::::2;::::0;;15365:2:1;156284:80:0::2;::::0;::::2;15347:21:1::0;15404:2;15384:18;;;15377:30;15443:12;15423:18;;;15416:40;15473:18;;156284:80:0::2;15163:334:1::0;156284:80:0::2;156375:39;::::0;::::2;;::::0;;;:22:::2;:39;::::0;;;;:59;;156418:16;;156375:39;:59:::2;::::0;156418:16;;156375:59:::2;:::i;:::-;;;;;;;;156466:16;156445:17;;:37;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;156568:4:0::2;::::0;156532:72:::2;::::0;156568:4:::2;;156575:15:::0;156592:11;156532:27:::2;:72::i;:::-;156177:435;142290:1:::1;156060:552:::0;;:::o;146861:322::-;146932:21;;146904:11;;146932:21;;146928:236;;;-1:-1:-1;146961:17:0;;146861:322;:::o;146928:236::-;147056:1;147050:7;;147149:3;147124:21;;147118:3;:27;;;;:::i;:::-;147117:35;;;;:::i;:::-;147111:41;;146861:322;:::o;36051:271::-;36120:14;;;;36106:10;:28;36098:94;;;;;;;15704:2:1;36098:94:0;;;15686:21:1;15743:2;15723:18;;;15716:30;15782:34;15762:18;;;15755:62;15853:23;15833:18;;;15826:51;15894:19;;36098:94:0;15502:417:1;36098:94:0;36221:5;;;36228:14;36208:35;;;36221:5;;;;16159:34:1;;36228:14:0;;;;16224:2:1;16209:18;;16202:43;36208:35:0;;16071:18:1;36208:35:0;;;;;;;36262:14;;;;36254:22;;;;;;36262:14;;;36254:22;;;;36287:27;;;36051:271::o;144815:675::-;144975:5;;:43;;;;;145002:15;144975:43;;;939:25:1;144864:19:0;;;;;;144975:5;;;:26;;912:18:1;;144975:43:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;145045:16;145063;145085:5;;;;;;;;;;;:17;;;:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;145123:14:0;;145044:60;;;;;-1:-1:-1;145044:60:0;;;-1:-1:-1;145123:14:0;;;;;145119:250;;;145171:8;145157:22;;145211:8;145198:21;;145119:250;;;145305:8;145291:22;;145345:8;145332:21;;145119:250;-1:-1:-1;145472:10:0;;-1:-1:-1;145450:18:0;:11;145464:4;145450:18;:::i;:::-;145449:33;;;;:::i;:::-;145437:45;;144815:675;;;:::o;155527:255::-;142214:5;;;;142200:10;:19;;:53;;-1:-1:-1;142237:16:0;;;;142223:10;:30;142200:53;142192:87;;;;;;;6867:2:1;142192:87:0;;;6849:21:1;6906:2;6886:18;;;6879:30;6945:23;6925:18;;;6918:51;6986:18;;142192:87:0;6665:345:1;142192:87:0;155614:8:::1;155610:164;;;155677:7;::::0;155690:32:::1;::::0;;;;155716:4:::1;155690:32;::::0;::::1;2721:74:1::0;155677:7:0::1;::::0;;::::1;::::0;:12:::1;::::0;:7;;155690:17:::1;::::0;2694:18:1;;155690:32:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;155677:46;;;;;;;;;;;;;939:25:1::0;;927:2;912:18;;793:177;155677:46:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;155527:255:::0;;:::o;155610:164::-:1;155750:7;::::0;:24:::1;::::0;;;;::::1;::::0;::::1;939:25:1::0;;;155750:7:0::1;::::0;;::::1;::::0;:12:::1;::::0;912:18:1;;155750:24:0::1;793:177:1::0;155610:164:0::1;155527:255:::0;;:::o;154969:458::-;142214:5;;;;142200:10;:19;;:53;;-1:-1:-1;142237:16:0;;;;142223:10;:30;142200:53;142192:87;;;;;;;6867:2:1;142192:87:0;;;6849:21:1;6906:2;6886:18;;;6879:30;6945:23;6925:18;;;6918:51;6986:18;;142192:87:0;6665:345:1;142192:87:0;155125:5:::1;::::0;155102:15:::1;::::0;155125:5:::1;;:38;155164:22:::0;;:64:::1;;155211:17;155164:64;;;155189:19;;155164:64;155125:104;;;;;;;;;;;;;939:25:1::0;;927:2;912:18;;793:177;155125:104:0::1;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;155101:128;;;;155352:10;:38;;;;-1:-1:-1::0;155367:22:0;;155352:38:::1;155348:71;;;155392:19;:27:::0;;;::::1;::::0;;155052:375:::1;154969:458:::0;:::o;160920:300::-;142214:5;;;;142200:10;:19;;:53;;-1:-1:-1;142237:16:0;;;;142223:10;:30;142200:53;142192:87;;;;;;;6867:2:1;142192:87:0;;;6849:21:1;6906:2;6886:18;;;6879:30;6945:23;6925:18;;;6918:51;6986:18;;142192:87:0;6665:345:1;142192:87:0;161136:5:::1;::::0;161094:61:::1;::::0;161122:12;;161136:5:::1;;161143:11:::0;161094:27:::1;:61::i;:::-;161171:41;::::0;;13979:42:1;13967:55;;13949:74;;14054:2;14039:18;;14032:34;;;161171:41:0::1;::::0;13922:18:1;161171:41:0::1;;;;;;;160920:300:::0;;:::o;157530:665::-;142214:5;;;;142200:10;:19;;:53;;-1:-1:-1;142237:16:0;;;;142223:10;:30;142200:53;142192:87;;;;;;;6867:2:1;142192:87:0;;;6849:21:1;6906:2;6886:18;;;6879:30;6945:23;6925:18;;;6918:51;6986:18;;142192:87:0;6665:345:1;142192:87:0;157609:25:::1;::::0;::::1;157601:59;;;::::0;::::1;::::0;;17551:2:1;157601:59:0::1;::::0;::::1;17533:21:1::0;17590:2;17570:18;;;17563:30;17629:23;17609:18;;;17602:51;17670:18;;157601:59:0::1;17349:345:1::0;157601:59:0::1;157679:17;::::0;::::1;;::::0;;;:4:::1;:17;::::0;;;;;::::1;;:25;;:17:::0;:25:::1;157671:57;;;::::0;::::1;::::0;;17901:2:1;157671:57:0::1;::::0;::::1;17883:21:1::0;17940:2;17920:18;;;17913:30;17979:21;17959:18;;;17952:49;18018:18;;157671:57:0::1;17699:343:1::0;157671:57:0::1;157792:17;::::0;::::1;;::::0;;;:4:::1;:17;::::0;;;;157785:24;;;::::1;::::0;;157888:259:::1;157909:10;:17:::0;157905:21;::::1;157888:259;;;157969:11;157952:28;;:10;157963:1;157952:13;;;;;;;;:::i;:::-;;::::0;;;::::1;::::0;;;::::1;::::0;::::1;;:28:::0;157948:188:::1;;158025:1;158001:10;158012:1;158001:13;;;;;;;;:::i;:::-;;;;;;;;;:26;;;;;;;;;;;;;;;;;;158115:5;;157948:188;157928:3:::0;::::1;::::0;::::1;:::i;:::-;;;;157888:259;;;-1:-1:-1::0;158164:23:0::1;::::0;2751:42:1;2739:55;;2721:74;;158164:23:0::1;::::0;2709:2:1;2694:18;158164:23:0::1;2545:256:1::0;158688:440:0;142214:5;;;;142200:10;:19;;:53;;-1:-1:-1;142237:16:0;;;;142223:10;:30;142200:53;142192:87;;;;;;;6867:2:1;142192:87:0;;;6849:21:1;6906:2;6886:18;;;6879:30;6945:23;6925:18;;;6918:51;6986:18;;142192:87:0;6665:345:1;142192:87:0;158851:19:::1;::::0;;;::::1;;;158847:66;;;158872:41;158893:19;;158872:20;:41::i;:::-;158974:5;:36:::0;;;::::1;;::::0;::::1;::::0;;::::1;::::0;;;159021:11:::1;:26:::0;;;159095:25:::1;::::0;;;;;;;:23:::1;::::0;:25:::1;::::0;;::::1;::::0;::::1;::::0;;;;;;;;;-1:-1:-1;158974:36:0;159095:25:::1;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;159080:40;::::0;:12;:40:::1;:::i;:::-;159058:19;:62:::0;-1:-1:-1;;158688:440:0:o;147845:823::-;147898:23;147933:21;147965:17;147993:27;148051:16;:14;:16::i;:::-;148039:28;;148094:10;;;;;;;;;;;:23;;;:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;148078:41;;148130:18;148151:7;;;;;;;;;;;:19;;;:21;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;148130:42;;148201:13;148189:9;:25;148185:476;;;141754:4;148287:10;148258:25;148270:13;148258:9;:25;:::i;:::-;148257:40;;;;:::i;:::-;148256:60;;;;:::i;:::-;148230:87;-1:-1:-1;148407:9:0;141860:3;148356:25;148368:13;148407:9;148356:25;:::i;:::-;148355:48;;;;:::i;:::-;148354:62;;;;:::i;:::-;148332:84;;148185:476;;;141754:4;148520:10;148491:25;148507:9;148491:13;:25;:::i;:::-;148490:40;;;;:::i;:::-;148489:60;;;;:::i;:::-;148477:73;;:2;:73;:::i;:::-;148458:92;-1:-1:-1;148640:9:0;141860:3;148589:25;148640:9;148589:13;:25;:::i;:::-;148588:48;;;;:::i;:::-;148587:62;;;;:::i;:::-;148565:84;;148185:476;148028:640;147845:823;;;;:::o;159596:205::-;142214:5;;;;142200:10;:19;;:53;;-1:-1:-1;142237:16:0;;;;142223:10;:30;142200:53;142192:87;;;;;;;6867:2:1;142192:87:0;;;6849:21:1;6906:2;6886:18;;;6879:30;6945:23;6925:18;;;6918:51;6986:18;;142192:87:0;6665:345:1;142192:87:0;159706:20:::1;:44:::0;;;;159761:14:::1;:32:::0;159596:205::o;151479:3173::-;151604:19;142214:5;;151604:19;;142214:5;;142200:10;:19;;:53;;-1:-1:-1;142237:16:0;;;;142223:10;:30;142200:53;142192:87;;;;;;;6867:2:1;142192:87:0;;;6849:21:1;6906:2;6886:18;;;6879:30;6945:23;6925:18;;;6918:51;6986:18;;142192:87:0;6665:345:1;142192:87:0;151731:1:::1;151715:13;:17;151714:41;;;;;151753:1;151738:12;:16;151714:41;151712:44;151704:87;;;::::0;::::1;::::0;;19298:2:1;151704:87:0::1;::::0;::::1;19280:21:1::0;19337:2;19317:18;;;19310:30;19376:32;19356:18;;;19349:60;19426:18;;151704:87:0::1;19096:354:1::0;151704:87:0::1;152072:19;::::0;;;::::1;;;152068:70;;;152093:5;::::0;152118:19:::1;::::0;152093:45:::1;::::0;;;;:5:::1;::::0;;::::1;::::0;:24:::1;::::0;:45:::1;::::0;::::1;;939:25:1::0;;;927:2;912:18;;793:177;152093:45:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;152068:70;152213:22;152239:12;:10;:12::i;:::-;152206:45;;;;;152386:14;;152368;:32;;152360:61;;;::::0;::::1;::::0;;19657:2:1;152360:61:0::1;::::0;::::1;19639:21:1::0;19696:2;19676:18;;;19669:30;19735:18;19715;;;19708:46;19771:18;;152360:61:0::1;19455:340:1::0;152360:61:0::1;152487:5;;;;;;;;;;;:20;;;:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;152465:19;:44:::0;152540:16;;152536:1919:::1;;152690:12;152677:25;;152786:1;152773:10;:14;152765:51;;;::::0;::::1;::::0;;20002:2:1;152765:51:0::1;::::0;::::1;19984:21:1::0;20041:2;20021:18;;;20014:30;20080:26;20060:18;;;20053:54;20124:18;;152765:51:0::1;19800:348:1::0;152765:51:0::1;152892:19;;152878:10;:33;;152870:63;;;::::0;::::1;::::0;;20355:2:1;152870:63:0::1;::::0;::::1;20337:21:1::0;20394:2;20374:18;;;20367:30;20433:19;20413:18;;;20406:47;20470:18;;152870:63:0::1;20153:341:1::0;152870:63:0::1;152988:7;::::0;:46:::1;::::0;;;;153016:4:::1;152988:46;::::0;::::1;13949:74:1::0;14039:18;;;14032:34;;;152988:7:0::1;::::0;;::::1;::::0;:19:::1;::::0;13922:18:1;;152988:46:0::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;153093:7:0::1;::::0;153117:5:::1;::::0;153093:43:::1;::::0;;;;:7:::1;153117:5:::0;;::::1;153093:43;::::0;::::1;13949:74:1::0;14039:18;;;14032:34;;;153093:7:0;::::1;::::0;-1:-1:-1;153093:15:0::1;::::0;-1:-1:-1;13922:18:1;;153093:43:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;153199:14:0::1;::::0;;;::::1;;;153195:339;;;153238:5;::::0;::::1;;:26;153265:10:::0;153277:22;:65:::1;;153323:19;;153277:65;;;153302:18;153277:65;153238:105;::::0;;::::1;::::0;;;;;;::::1;::::0;::::1;5431:25:1::0;;;;5472:18;;;5465:34;5404:18;;153238:105:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;152536:1919;;153195:339;153409:5;::::0;::::1;;:26;153436:10:::0;153448:22;:65:::1;;153494:19;;153448:65;;152536:1919;153694:13;153680:27;;153788:1;153774:11;:15;153766:53;;;::::0;::::1;::::0;;20951:2:1;153766:53:0::1;::::0;::::1;20933:21:1::0;20990:2;20970:18;;;20963:30;21029:27;21009:18;;;21002:55;21074:18;;153766:53:0::1;20749:349:1::0;153766:53:0::1;153896:20;;153881:11;:35;;153873:66;;;::::0;::::1;::::0;;21305:2:1;153873:66:0::1;::::0;::::1;21287:21:1::0;21344:2;21324:18;;;21317:30;21383:20;21363:18;;;21356:48;21421:18;;153873:66:0::1;21103:342:1::0;153873:66:0::1;153999:4;::::0;;154020:5:::1;::::0;153999:41:::1;::::0;;;;:4:::1;154020:5:::0;;::::1;153999:41:::0;;::::1;13949:74:1::0;;;;14039:18;;;14032:34;;;153999:4:0::1;::::0;:12:::1;::::0;13922:18:1;;153999:41:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;154103:14:0::1;::::0;;;::::1;;;154099:341;;;154142:5;::::0;::::1;;:26;154169:11:::0;154182:22;:65:::1;;154228:19;;154182:65;;154099:341;154314:5;::::0;::::1;;:26;154341:11:::0;154354:22;:65:::1;;154400:19;;154354:65;;;154379:18;154354:65;154314:106;::::0;;::::1;::::0;;;;;;::::1;::::0;::::1;5431:25:1::0;;;;5472:18;;;5465:34;5404:18;;154314:106:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;154099:341;154525:19;:26:::0;;;::::1;::::0;::::1;::::0;;154582:19:::1;::::0;154569:75:::1;::::0;;5092:25:1;;;5148:2;5133:18;;5126:34;;;5176:18;;5169:34;;;154628:15:0::1;5234:2:1::0;5219:18;;5212:34;154569:75:0::1;::::0;5079:3:1;5064:19;154569:75:0::1;;;;;;;151645:3007;151479:3173:::0;;;;;;:::o;157176:323::-;142214:5;;;;142200:10;:19;;:53;;-1:-1:-1;142237:16:0;;;;142223:10;:30;142200:53;142192:87;;;;;;;6867:2:1;142192:87:0;;;6849:21:1;6906:2;6886:18;;;6879:30;6945:23;6925:18;;;6918:51;6986:18;;142192:87:0;6665:345:1;142192:87:0;157252:25:::1;::::0;::::1;157244:59;;;::::0;::::1;::::0;;17551:2:1;157244:59:0::1;::::0;::::1;17533:21:1::0;17590:2;17570:18;;;17563:30;17629:23;17609:18;;;17602:51;17670:18;;157244:59:0::1;17349:345:1::0;157244:59:0::1;157324:17;::::0;::::1;;::::0;;;:4:::1;:17;::::0;;;;;::::1;;:26;157316:61;;;::::0;::::1;::::0;;22048:2:1;157316:61:0::1;::::0;::::1;22030:21:1::0;22087:2;22067:18;;;22060:30;22126:24;22106:18;;;22099:52;22168:18;;157316:61:0::1;21846:346:1::0;157316:61:0::1;157388:17;::::0;::::1;;::::0;;;:4:::1;:17;::::0;;;;;;;:24;;;::::1;157408:4;157388:24:::0;;::::1;::::0;;;157424:10:::1;:28:::0;;;;::::1;::::0;;;;;;;;::::1;::::0;;;::::1;::::0;::::1;::::0;;157470:21;;2721:74:1;;;157470:21:0::1;::::0;2694:18:1;157470:21:0::1;2545:256:1::0;147234:554:0;147282:21;147305;147328:17;147358;147378:16;:14;:16::i;:::-;147358:36;;147421:10;;;;;;;;;;;:23;;;:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;147405:41;;147475:13;147463:9;:25;147459:255;;;147573:9;141860:3;147522:25;147534:13;147573:9;147522:25;:::i;:::-;147521:48;;;;:::i;:::-;147520:62;;;;:::i;:::-;147504:78;;147459:255;;;147693:9;141860:3;147642:25;147693:9;147642:13;:25;:::i;:::-;147641:48;;;;:::i;:::-;147640:62;;;;:::i;:::-;147624:78;;147459:255;147759:20;;147742:13;:37;;147726:54;;147347:441;147234:554;;;:::o;160658:133::-;142214:5;;;;142200:10;:19;;:53;;-1:-1:-1;142237:16:0;;;;142223:10;:30;142200:53;142192:87;;;;;;;6867:2:1;142192:87:0;;;6849:21:1;6906:2;6886:18;;;6879:30;6945:23;6925:18;;;6918:51;6986:18;;142192:87:0;6665:345:1;142192:87:0;160743:16:::1;:40:::0;;;::::1;;::::0;;;::::1;::::0;;;::::1;::::0;;160658:133::o;154660:301::-;142214:5;;;;142200:10;:19;;:53;;-1:-1:-1;142237:16:0;;;;142223:10;:30;142200:53;142192:87;;;;;;;6867:2:1;142192:87:0;;;6849:21:1;6906:2;6886:18;;;6879:30;6945:23;6925:18;;;6918:51;6986:18;;142192:87:0;6665:345:1;142192:87:0;154777:5:::1;::::0;::::1;;:24;154802:22:::0;;:64:::1;;154849:17;154802:64;;;154827:19;;154802:64;154777:90;;;;;;;;;;;;;939:25:1::0;;927:2;912:18;;793:177;154777:90:0::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;-1:-1:-1::0;;154926:19:0::1;:27:::0;;;::::1;::::0;;-1:-1:-1;;;154660:301:0:o;150981:443::-;151056:16;151096:35;151110:6;151118:12;151096:13;:35::i;:::-;151212:7;;151085:46;;-1:-1:-1;151172:84:0;;151212:7;;151222:10;151242:4;151249:6;151172:31;:84::i;:::-;151341:4;;151305:64;;151341:4;;151348:10;151360:8;151305:27;:64::i;:::-;151387:29;;;5431:25:1;;;5487:2;5472:18;;5465:34;;;151387:29:0;;5404:18:1;151387:29:0;5257:248:1;159136:92:0;142214:5;;;;142200:10;:19;;:53;;-1:-1:-1;142237:16:0;;;;142223:10;:30;142200:53;142192:87;;;;;;;6867:2:1;142192:87:0;;;6849:21:1;6906:2;6886:18;;;6879:30;6945:23;6925:18;;;6918:51;6986:18;;142192:87:0;6665:345:1;142192:87:0;159208:12:::1;::::0;;159192:28;;::::1;159208:12;::::0;;::::1;159207:13;159192:28;::::0;;159136:92::o;144339:369::-;144386:7;144407:14;144423:9;144436:17;144455:22;144481:15;;;;;;;;;;;:31;;;:33;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;144406:108;;;;;;;;;144542:1;144533:5;:10;;:27;;;;-1:-1:-1;144547:13:0;;;144533:27;:57;;;;;144583:7;144564:26;;:15;:26;;;;144533:57;144525:93;;;;;;;7879:2:1;144525:93:0;;;7861:21:1;7918:2;7898:18;;;7891:30;7957:25;7937:18;;;7930:53;8000:18;;144525:93:0;7677:347:1;144525:93:0;144672:26;;144666:32;;:2;:32;:::i;146537:302::-;146606:19;;146578:11;;146606:19;;146602:230;;;-1:-1:-1;146633:15:0;;146861:322;:::o;146602:230::-;146726:1;146720:7;;146817:3;146794:19;;146788:3;:25;;;;:::i;160424:226::-;142214:5;;;;142200:10;:19;;:53;;-1:-1:-1;142237:16:0;;;;142223:10;:30;142200:53;142192:87;;;;;;;6867:2:1;142192:87:0;;;6849:21:1;6906:2;6886:18;;;6879:30;6945:23;6925:18;;;6918:51;6986:18;;142192:87:0;6665:345:1;142192:87:0;160545:20:::1;:44:::0;;;;160600:19:::1;:42:::0;160424:226::o;159236:98::-;142214:5;;;;142200:10;:19;;:53;;-1:-1:-1;142237:16:0;;;;142223:10;:30;142200:53;142192:87;;;;;;;6867:2:1;142192:87:0;;;6849:21:1;6906:2;6886:18;;;6879:30;6945:23;6925:18;;;6918:51;6986:18;;142192:87:0;6665:345:1;142192:87:0;159312:14:::1;::::0;;159294:32;;::::1;159312:14;::::0;;;::::1;;;159311:15;159294:32:::0;;::::1;;::::0;;159236:98::o;108690:402::-;108915:51;;;108904:10;22478:15:1;;;108915:51:0;;;22460:34:1;22530:15;;;22510:18;;;22503:43;22562:18;;;;22555:34;;;108915:51:0;;;;;;;;;;22372:18:1;;;;108915:51:0;;;;;;;;;;;;;108904:63;;-1:-1:-1;;;;108904:10:0;;;;:63;;108915:51;108904:63;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;108868:99;;;;108986:7;:57;;;;-1:-1:-1;108998:11:0;;:16;;:44;;;109029:4;109018:24;;;;;;;;;;;;:::i;:::-;108978:106;;;;;;;23233:2:1;108978:106:0;;;23215:21:1;23272:2;23252:18;;;23245:30;23311:34;23291:18;;;23284:62;23382:6;23362:18;;;23355:34;23406:19;;108978:106:0;23031:400:1;108321:361:0;108516:45;;;108505:10;13967:55:1;;;108516:45:0;;;13949:74:1;14039:18;;;;14032:34;;;108516:45:0;;;;;;;;;;13922:18:1;;;;108516:45:0;;;;;;;;;;;;;108505:57;;-1:-1:-1;;;;108505:10:0;;;;:57;;108516:45;108505:57;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;108469:93;;;;108581:7;:57;;;;-1:-1:-1;108593:11:0;;:16;;:44;;;108624:4;108613:24;;;;;;;;;;;;:::i;:::-;108573:101;;;;;;;23638:2:1;108573:101:0;;;23620:21:1;23677:2;23657:18;;;23650:30;23716:33;23696:18;;;23689:61;23767:18;;108573:101:0;23436:355:1;108573:101:0;108391:291;;108321:361;;;:::o;14:118:1:-;100:5;93:13;86:21;79:5;76:32;66:60;;122:1;119;112:12;66:60;14:118;:::o;137:651::-;235:6;243;251;259;267;275;328:3;316:9;307:7;303:23;299:33;296:53;;;345:1;342;335:12;296:53;384:9;371:23;403:28;425:5;403:28;:::i;:::-;450:5;-1:-1:-1;502:2:1;487:18;;474:32;;-1:-1:-1;553:2:1;538:18;;525:32;;-1:-1:-1;609:2:1;594:18;;581:32;622:30;581:32;622:30;:::i;:::-;137:651;;;;-1:-1:-1;137:651:1;;725:3;710:19;;697:33;;777:3;762:19;;;749:33;;-1:-1:-1;137:651:1;-1:-1:-1;;137:651:1:o;975:154::-;1061:42;1054:5;1050:54;1043:5;1040:65;1030:93;;1119:1;1116;1109:12;1134:529;1211:6;1219;1227;1280:2;1268:9;1259:7;1255:23;1251:32;1248:52;;;1296:1;1293;1286:12;1248:52;1335:9;1322:23;1354:31;1379:5;1354:31;:::i;:::-;1404:5;-1:-1:-1;1461:2:1;1446:18;;1433:32;1474:33;1433:32;1474:33;:::i;:::-;1526:7;-1:-1:-1;1585:2:1;1570:18;;1557:32;1598:33;1557:32;1598:33;:::i;:::-;1650:7;1640:17;;;1134:529;;;;;:::o;1860:247::-;1919:6;1972:2;1960:9;1951:7;1947:23;1943:32;1940:52;;;1988:1;1985;1978:12;1940:52;2027:9;2014:23;2046:31;2071:5;2046:31;:::i;:::-;2096:5;1860:247;-1:-1:-1;;;1860:247:1:o;2292:248::-;2360:6;2368;2421:2;2409:9;2400:7;2396:23;2392:32;2389:52;;;2437:1;2434;2427:12;2389:52;-1:-1:-1;;2460:23:1;;;2530:2;2515:18;;;2502:32;;-1:-1:-1;2292:248:1:o;2806:180::-;2865:6;2918:2;2906:9;2897:7;2893:23;2889:32;2886:52;;;2934:1;2931;2924:12;2886:52;-1:-1:-1;2957:23:1;;2806:180;-1:-1:-1;2806:180:1:o;3662:315::-;3730:6;3738;3791:2;3779:9;3770:7;3766:23;3762:32;3759:52;;;3807:1;3804;3797:12;3759:52;3846:9;3833:23;3865:31;3890:5;3865:31;:::i;:::-;3915:5;3967:2;3952:18;;;;3939:32;;-1:-1:-1;;;3662:315:1:o;4306:309::-;4371:6;4379;4432:2;4420:9;4411:7;4407:23;4403:32;4400:52;;;4448:1;4445;4438:12;4400:52;4487:9;4474:23;4506:28;4528:5;4506:28;:::i;5510:316::-;5587:6;5595;5603;5656:2;5644:9;5635:7;5631:23;5627:32;5624:52;;;5672:1;5669;5662:12;5624:52;-1:-1:-1;;5695:23:1;;;5765:2;5750:18;;5737:32;;-1:-1:-1;5816:2:1;5801:18;;;5788:32;;5510:316;-1:-1:-1;5510:316:1:o;7015:179::-;7093:13;;7146:22;7135:34;;7125:45;;7115:73;;7184:1;7181;7174:12;7115:73;7015:179;;;:::o;7199:473::-;7302:6;7310;7318;7326;7334;7387:3;7375:9;7366:7;7362:23;7358:33;7355:53;;;7404:1;7401;7394:12;7355:53;7427:39;7456:9;7427:39;:::i;:::-;7417:49;;7506:2;7495:9;7491:18;7485:25;7475:35;;7550:2;7539:9;7535:18;7529:25;7519:35;;7594:2;7583:9;7579:18;7573:25;7563:35;;7617:49;7661:3;7650:9;7646:19;7617:49;:::i;:::-;7607:59;;7199:473;;;;;;;;:::o;8029:184::-;8081:77;8078:1;8071:88;8178:4;8175:1;8168:15;8202:4;8199:1;8192:15;8218:482;8307:1;8350:5;8307:1;8364:330;8385:7;8375:8;8372:21;8364:330;;;8504:4;8436:66;8432:77;8426:4;8423:87;8420:113;;;8513:18;;:::i;:::-;8563:7;8553:8;8549:22;8546:55;;;8583:16;;;;8546:55;8662:22;;;;8622:15;;;;8364:330;;;8368:3;8218:482;;;;;:::o;8705:866::-;8754:5;8784:8;8774:80;;-1:-1:-1;8825:1:1;8839:5;;8774:80;8873:4;8863:76;;-1:-1:-1;8910:1:1;8924:5;;8863:76;8955:4;8973:1;8968:59;;;;9041:1;9036:130;;;;8948:218;;8968:59;8998:1;8989:10;;9012:5;;;9036:130;9073:3;9063:8;9060:17;9057:43;;;9080:18;;:::i;:::-;-1:-1:-1;;9136:1:1;9122:16;;9151:5;;8948:218;;9250:2;9240:8;9237:16;9231:3;9225:4;9222:13;9218:36;9212:2;9202:8;9199:16;9194:2;9188:4;9185:12;9181:35;9178:77;9175:159;;;-1:-1:-1;9287:19:1;;;9319:5;;9175:159;9366:34;9391:8;9385:4;9366:34;:::i;:::-;9496:6;9428:66;9424:79;9415:7;9412:92;9409:118;;;9507:18;;:::i;:::-;9545:20;;-1:-1:-1;8705:866:1;;;;;:::o;9576:131::-;9636:5;9665:36;9692:8;9686:4;9665:36;:::i;9712:228::-;9752:7;9878:1;9810:66;9806:74;9803:1;9800:81;9795:1;9788:9;9781:17;9777:105;9774:131;;;9885:18;;:::i;:::-;-1:-1:-1;9925:9:1;;9712:228::o;9945:274::-;9985:1;10011;10001:189;;10046:77;10043:1;10036:88;10147:4;10144:1;10137:15;10175:4;10172:1;10165:15;10001:189;-1:-1:-1;10204:9:1;;9945:274::o;10224:273::-;10292:6;10345:2;10333:9;10324:7;10320:23;10316:32;10313:52;;;10361:1;10358;10351:12;10313:52;10393:9;10387:16;10443:4;10436:5;10432:16;10425:5;10422:27;10412:55;;10463:1;10460;10453:12;11607:125;11647:4;11675:1;11672;11669:8;11666:34;;;11680:18;;:::i;:::-;-1:-1:-1;11717:9:1;;11607:125::o;13112:184::-;13182:6;13235:2;13223:9;13214:7;13210:23;13206:32;13203:52;;;13251:1;13248;13241:12;13203:52;-1:-1:-1;13274:16:1;;13112:184;-1:-1:-1;13112:184:1:o;13301:128::-;13341:3;13372:1;13368:6;13365:1;13362:13;13359:39;;;13378:18;;:::i;:::-;-1:-1:-1;13414:9:1;;13301:128::o;14417:369::-;14456:4;14492:1;14489;14485:9;14601:1;14533:66;14529:74;14526:1;14522:82;14517:2;14510:10;14506:99;14503:125;;;14608:18;;:::i;:::-;14727:1;14659:66;14655:74;14652:1;14648:82;14644:2;14640:91;14637:117;;;14734:18;;:::i;:::-;-1:-1:-1;;14771:9:1;;14417:369::o;14791:367::-;14830:3;14865:1;14862;14858:9;14974:1;14906:66;14902:74;14899:1;14895:82;14890:2;14883:10;14879:99;14876:125;;;14981:18;;:::i;:::-;15100:1;15032:66;15028:74;15025:1;15021:82;15017:2;15013:91;15010:117;;;15107:18;;:::i;:::-;-1:-1:-1;;15143:9:1;;14791:367::o;16256:188::-;16335:13;;16388:30;16377:42;;16367:53;;16357:81;;16434:1;16431;16424:12;16449:450;16536:6;16544;16552;16605:2;16593:9;16584:7;16580:23;16576:32;16573:52;;;16621:1;16618;16611:12;16573:52;16644:40;16674:9;16644:40;:::i;:::-;16634:50;;16703:49;16748:2;16737:9;16733:18;16703:49;:::i;:::-;16693:59;;16795:2;16784:9;16780:18;16774:25;16839:10;16832:5;16828:22;16821:5;16818:33;16808:61;;16865:1;16862;16855:12;16904:440;16989:6;16997;17005;17058:2;17046:9;17037:7;17033:23;17029:32;17026:52;;;17074:1;17071;17064:12;17026:52;17106:9;17100:16;17125:28;17147:5;17125:28;:::i;:::-;17222:2;17207:18;;17201:25;17172:5;;-1:-1:-1;17235:33:1;17201:25;17235:33;:::i;:::-;17287:7;17277:17;;;17334:2;17323:9;17319:18;17313:25;17303:35;;16904:440;;;;;:::o;18047:184::-;18099:77;18096:1;18089:88;18196:4;18193:1;18186:15;18220:4;18217:1;18210:15;18236:195;18275:3;18306:66;18299:5;18296:77;18293:103;;18376:18;;:::i;:::-;-1:-1:-1;18423:1:1;18412:13;;18236:195::o;18436:655::-;18475:7;18507:66;18599:1;18596;18592:9;18627:1;18624;18620:9;18672:1;18668:2;18664:10;18661:1;18658:17;18653:2;18649;18645:11;18641:35;18638:61;;;18679:18;;:::i;:::-;18718:66;18810:1;18807;18803:9;18857:1;18853:2;18848:11;18845:1;18841:19;18836:2;18832;18828:11;18824:37;18821:63;;;18864:18;;:::i;:::-;18910:1;18907;18903:9;18893:19;;18957:1;18953:2;18948:11;18945:1;18941:19;18936:2;18932;18928:11;18924:37;18921:63;;;18964:18;;:::i;:::-;19029:1;19025:2;19020:11;19017:1;19013:19;19008:2;19004;19000:11;18996:37;18993:63;;;19036:18;;:::i;:::-;-1:-1:-1;;;19076:9:1;;;;;18436:655;-1:-1:-1;;;18436:655:1:o;20499:245::-;20566:6;20619:2;20607:9;20598:7;20594:23;20590:32;20587:52;;;20635:1;20632;20625:12;20587:52;20667:9;20661:16;20686:28;20708:5;20686:28;:::i;22600:426::-;22729:3;22767:6;22761:13;22792:1;22802:129;22816:6;22813:1;22810:13;22802:129;;;22914:4;22898:14;;;22894:25;;22888:32;22875:11;;;22868:53;22831:12;22802:129;;;22949:6;22946:1;22943:13;22940:48;;;22984:1;22975:6;22970:3;22966:16;22959:27;22940:48;-1:-1:-1;23004:16:1;;;;;22600:426;-1:-1:-1;;22600:426:1:o
Swarm Source
ipfs://208fed16333a2046b1f9866232ee4988528031799d47c7654db9f03ac633a279
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
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.