Overview
ETH Balance
ETH Value
$0.00Multichain Info
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Grant Role | 1010502 | 141 days ago | IN | 0 ETH | 0.00000005 |
View more zero value Internal Transactions in Advanced View mode
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.8.20; import "@openzeppelin/contracts/governance/TimelockController.sol"; import "./PolygonZkEVM.sol"; /** * @dev Contract module which acts as a timelocked controller. * This gives time for users of the controlled contract to exit before a potentially dangerous maintenance operation is applied. * If emergency mode of the zkevm contract system is active, this timelock have no delay. */ contract PolygonZkEVMTimelock is TimelockController { // Polygon ZK-EVM address. Will be used to check if it's on emergency state. PolygonZkEVM public immutable polygonZkEVM; /** * @notice Constructor of timelock * @param minDelay initial minimum delay for operations * @param proposers accounts to be granted proposer and canceller roles * @param executors accounts to be granted executor role * @param admin optional account to be granted admin role; disable with zero address * @param _polygonZkEVM polygonZkEVM address **/ constructor( uint256 minDelay, address[] memory proposers, address[] memory executors, address admin, PolygonZkEVM _polygonZkEVM ) TimelockController(minDelay, proposers, executors, admin) { polygonZkEVM = _polygonZkEVM; } /** * @dev Returns the minimum delay for an operation to become valid. * * This value can be changed by executing an operation that calls `updateDelay`. * If Polygon ZK-EVM is on emergency state the minDelay will be 0 instead. */ function getMinDelay() public view override returns (uint256 duration) { if (address(polygonZkEVM) != address(0) && polygonZkEVM.isEmergencyState()) { return 0; } else { return super.getMinDelay(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20PermitUpgradeable { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; import "../extensions/draft-IERC20PermitUpgradeable.sol"; import "../../../utils/AddressUpgradeable.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20Upgradeable { using AddressUpgradeable for address; function safeTransfer( IERC20Upgradeable token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20Upgradeable token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20Upgradeable token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20Upgradeable token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20Upgradeable token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20PermitUpgradeable token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControl.sol"; import "../utils/Context.sol"; import "../utils/Strings.sol"; import "../utils/introspection/ERC165.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); _; } /** * @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 `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ */ function _checkRole(bytes32 role, address account) internal view virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", Strings.toHexString(account), " 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. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleRevoked} event. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been revoked `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. * * May emit a {RoleRevoked} event. */ function renounceRole(bytes32 role, address account) public virtual override { require(account == _msgSender(), "AccessControl: can only renounce roles for self"); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * May emit a {RoleGranted} event. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== * * NOTE: This function is deprecated in favor of {_grantRole}. */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { bytes32 previousAdminRole = getRoleAdmin(role); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface 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; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.2) (governance/TimelockController.sol) pragma solidity ^0.8.0; import "../access/AccessControl.sol"; import "../token/ERC721/IERC721Receiver.sol"; import "../token/ERC1155/IERC1155Receiver.sol"; import "../utils/Address.sol"; /** * @dev Contract module which acts as a timelocked controller. When set as the * owner of an `Ownable` smart contract, it enforces a timelock on all * `onlyOwner` maintenance operations. This gives time for users of the * controlled contract to exit before a potentially dangerous maintenance * operation is applied. * * By default, this contract is self administered, meaning administration tasks * have to go through the timelock process. The proposer (resp executor) role * is in charge of proposing (resp executing) operations. A common use case is * to position this {TimelockController} as the owner of a smart contract, with * a multisig or a DAO as the sole proposer. * * _Available since v3.3._ */ contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver { bytes32 public constant TIMELOCK_ADMIN_ROLE = keccak256("TIMELOCK_ADMIN_ROLE"); bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE"); bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE"); bytes32 public constant CANCELLER_ROLE = keccak256("CANCELLER_ROLE"); uint256 internal constant _DONE_TIMESTAMP = uint256(1); mapping(bytes32 => uint256) private _timestamps; uint256 private _minDelay; /** * @dev Emitted when a call is scheduled as part of operation `id`. */ event CallScheduled( bytes32 indexed id, uint256 indexed index, address target, uint256 value, bytes data, bytes32 predecessor, uint256 delay ); /** * @dev Emitted when a call is performed as part of operation `id`. */ event CallExecuted(bytes32 indexed id, uint256 indexed index, address target, uint256 value, bytes data); /** * @dev Emitted when operation `id` is cancelled. */ event Cancelled(bytes32 indexed id); /** * @dev Emitted when the minimum delay for future operations is modified. */ event MinDelayChange(uint256 oldDuration, uint256 newDuration); /** * @dev Initializes the contract with the following parameters: * * - `minDelay`: initial minimum delay for operations * - `proposers`: accounts to be granted proposer and canceller roles * - `executors`: accounts to be granted executor role * - `admin`: optional account to be granted admin role; disable with zero address * * IMPORTANT: The optional admin can aid with initial configuration of roles after deployment * without being subject to delay, but this role should be subsequently renounced in favor of * administration through timelocked proposals. Previous versions of this contract would assign * this admin to the deployer automatically and should be renounced as well. */ constructor( uint256 minDelay, address[] memory proposers, address[] memory executors, address admin ) { _setRoleAdmin(TIMELOCK_ADMIN_ROLE, TIMELOCK_ADMIN_ROLE); _setRoleAdmin(PROPOSER_ROLE, TIMELOCK_ADMIN_ROLE); _setRoleAdmin(EXECUTOR_ROLE, TIMELOCK_ADMIN_ROLE); _setRoleAdmin(CANCELLER_ROLE, TIMELOCK_ADMIN_ROLE); // self administration _setupRole(TIMELOCK_ADMIN_ROLE, address(this)); // optional admin if (admin != address(0)) { _setupRole(TIMELOCK_ADMIN_ROLE, admin); } // register proposers and cancellers for (uint256 i = 0; i < proposers.length; ++i) { _setupRole(PROPOSER_ROLE, proposers[i]); _setupRole(CANCELLER_ROLE, proposers[i]); } // register executors for (uint256 i = 0; i < executors.length; ++i) { _setupRole(EXECUTOR_ROLE, executors[i]); } _minDelay = minDelay; emit MinDelayChange(0, minDelay); } /** * @dev Modifier to make a function callable only by a certain role. In * addition to checking the sender's role, `address(0)` 's role is also * considered. Granting a role to `address(0)` is equivalent to enabling * this role for everyone. */ modifier onlyRoleOrOpenRole(bytes32 role) { if (!hasRole(role, address(0))) { _checkRole(role, _msgSender()); } _; } /** * @dev Contract might receive/hold ETH as part of the maintenance process. */ receive() external payable {} /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, AccessControl) returns (bool) { return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns whether an id correspond to a registered operation. This * includes both Pending, Ready and Done operations. */ function isOperation(bytes32 id) public view virtual returns (bool registered) { return getTimestamp(id) > 0; } /** * @dev Returns whether an operation is pending or not. */ function isOperationPending(bytes32 id) public view virtual returns (bool pending) { return getTimestamp(id) > _DONE_TIMESTAMP; } /** * @dev Returns whether an operation is ready or not. */ function isOperationReady(bytes32 id) public view virtual returns (bool ready) { uint256 timestamp = getTimestamp(id); return timestamp > _DONE_TIMESTAMP && timestamp <= block.timestamp; } /** * @dev Returns whether an operation is done or not. */ function isOperationDone(bytes32 id) public view virtual returns (bool done) { return getTimestamp(id) == _DONE_TIMESTAMP; } /** * @dev Returns the timestamp at with an operation becomes ready (0 for * unset operations, 1 for done operations). */ function getTimestamp(bytes32 id) public view virtual returns (uint256 timestamp) { return _timestamps[id]; } /** * @dev Returns the minimum delay for an operation to become valid. * * This value can be changed by executing an operation that calls `updateDelay`. */ function getMinDelay() public view virtual returns (uint256 duration) { return _minDelay; } /** * @dev Returns the identifier of an operation containing a single * transaction. */ function hashOperation( address target, uint256 value, bytes calldata data, bytes32 predecessor, bytes32 salt ) public pure virtual returns (bytes32 hash) { return keccak256(abi.encode(target, value, data, predecessor, salt)); } /** * @dev Returns the identifier of an operation containing a batch of * transactions. */ function hashOperationBatch( address[] calldata targets, uint256[] calldata values, bytes[] calldata payloads, bytes32 predecessor, bytes32 salt ) public pure virtual returns (bytes32 hash) { return keccak256(abi.encode(targets, values, payloads, predecessor, salt)); } /** * @dev Schedule an operation containing a single transaction. * * Emits a {CallScheduled} event. * * Requirements: * * - the caller must have the 'proposer' role. */ function schedule( address target, uint256 value, bytes calldata data, bytes32 predecessor, bytes32 salt, uint256 delay ) public virtual onlyRole(PROPOSER_ROLE) { bytes32 id = hashOperation(target, value, data, predecessor, salt); _schedule(id, delay); emit CallScheduled(id, 0, target, value, data, predecessor, delay); } /** * @dev Schedule an operation containing a batch of transactions. * * Emits one {CallScheduled} event per transaction in the batch. * * Requirements: * * - the caller must have the 'proposer' role. */ function scheduleBatch( address[] calldata targets, uint256[] calldata values, bytes[] calldata payloads, bytes32 predecessor, bytes32 salt, uint256 delay ) public virtual onlyRole(PROPOSER_ROLE) { require(targets.length == values.length, "TimelockController: length mismatch"); require(targets.length == payloads.length, "TimelockController: length mismatch"); bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt); _schedule(id, delay); for (uint256 i = 0; i < targets.length; ++i) { emit CallScheduled(id, i, targets[i], values[i], payloads[i], predecessor, delay); } } /** * @dev Schedule an operation that is to becomes valid after a given delay. */ function _schedule(bytes32 id, uint256 delay) private { require(!isOperation(id), "TimelockController: operation already scheduled"); require(delay >= getMinDelay(), "TimelockController: insufficient delay"); _timestamps[id] = block.timestamp + delay; } /** * @dev Cancel an operation. * * Requirements: * * - the caller must have the 'canceller' role. */ function cancel(bytes32 id) public virtual onlyRole(CANCELLER_ROLE) { require(isOperationPending(id), "TimelockController: operation cannot be cancelled"); delete _timestamps[id]; emit Cancelled(id); } /** * @dev Execute an (ready) operation containing a single transaction. * * Emits a {CallExecuted} event. * * Requirements: * * - the caller must have the 'executor' role. */ // This function can reenter, but it doesn't pose a risk because _afterCall checks that the proposal is pending, // thus any modifications to the operation during reentrancy should be caught. // slither-disable-next-line reentrancy-eth function execute( address target, uint256 value, bytes calldata payload, bytes32 predecessor, bytes32 salt ) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE) { bytes32 id = hashOperation(target, value, payload, predecessor, salt); _beforeCall(id, predecessor); _execute(target, value, payload); emit CallExecuted(id, 0, target, value, payload); _afterCall(id); } /** * @dev Execute an (ready) operation containing a batch of transactions. * * Emits one {CallExecuted} event per transaction in the batch. * * Requirements: * * - the caller must have the 'executor' role. */ // This function can reenter, but it doesn't pose a risk because _afterCall checks that the proposal is pending, // thus any modifications to the operation during reentrancy should be caught. // slither-disable-next-line reentrancy-eth function executeBatch( address[] calldata targets, uint256[] calldata values, bytes[] calldata payloads, bytes32 predecessor, bytes32 salt ) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE) { require(targets.length == values.length, "TimelockController: length mismatch"); require(targets.length == payloads.length, "TimelockController: length mismatch"); bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt); _beforeCall(id, predecessor); for (uint256 i = 0; i < targets.length; ++i) { address target = targets[i]; uint256 value = values[i]; bytes calldata payload = payloads[i]; _execute(target, value, payload); emit CallExecuted(id, i, target, value, payload); } _afterCall(id); } /** * @dev Execute an operation's call. */ function _execute( address target, uint256 value, bytes calldata data ) internal virtual { (bool success, ) = target.call{value: value}(data); require(success, "TimelockController: underlying transaction reverted"); } /** * @dev Checks before execution of an operation's calls. */ function _beforeCall(bytes32 id, bytes32 predecessor) private view { require(isOperationReady(id), "TimelockController: operation is not ready"); require(predecessor == bytes32(0) || isOperationDone(predecessor), "TimelockController: missing dependency"); } /** * @dev Checks after execution of an operation's calls. */ function _afterCall(bytes32 id) private { require(isOperationReady(id), "TimelockController: operation is not ready"); _timestamps[id] = _DONE_TIMESTAMP; } /** * @dev Changes the minimum timelock duration for future operations. * * Emits a {MinDelayChange} event. * * Requirements: * * - the caller must be the timelock itself. This can only be achieved by scheduling and later executing * an operation where the timelock is the target and the data is the ABI-encoded call to this function. */ function updateDelay(uint256 newDelay) external virtual { require(msg.sender == address(this), "TimelockController: caller must be timelock"); emit MinDelayChange(_minDelay, newDelay); _minDelay = newDelay; } /** * @dev See {IERC721Receiver-onERC721Received}. */ function onERC721Received( address, address, uint256, bytes memory ) public virtual override returns (bytes4) { return this.onERC721Received.selector; } /** * @dev See {IERC1155Receiver-onERC1155Received}. */ function onERC1155Received( address, address, uint256, uint256, bytes memory ) public virtual override returns (bytes4) { return this.onERC1155Received.selector; } /** * @dev See {IERC1155Receiver-onERC1155BatchReceived}. */ function onERC1155BatchReceived( address, address, uint256[] memory, uint256[] memory, bytes memory ) public virtual override returns (bytes4) { return this.onERC1155BatchReceived.selector; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev _Available since v3.1._ */ interface IERC1155Receiver is IERC165 { /** * @dev Handles the receipt of a single ERC1155 token type. This function is * called at the end of a `safeTransferFrom` after the balance has been updated. * * NOTE: To accept the transfer, this must return * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` * (i.e. 0xf23a6e61, or its own function selector). * * @param operator The address which initiated the transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param id The ID of the token being transferred * @param value The amount of tokens being transferred * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed */ function onERC1155Received( address operator, address from, uint256 id, uint256 value, bytes calldata data ) external returns (bytes4); /** * @dev Handles the receipt of a multiple ERC1155 token types. This function * is called at the end of a `safeBatchTransferFrom` after the balances have * been updated. * * NOTE: To accept the transfer(s), this must return * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` * (i.e. 0xbc197c81, or its own function selector). * * @param operator The address which initiated the batch transfer (i.e. msg.sender) * @param from The address which previously owned the token * @param ids An array containing ids of each token being transferred (order and length must match values array) * @param values An array containing amounts of each token being transferred (order and length must match ids array) * @param data Additional data with no specified format * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed */ function onERC1155BatchReceived( address operator, address from, uint256[] calldata ids, uint256[] calldata values, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @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; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/Math.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.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; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface 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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // ? `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // ? `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.20; import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; import "./interfaces/IVerifierRollup.sol"; import "./interfaces/IPolygonZkEVMGlobalExitRoot.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import "./interfaces/IPolygonZkEVMBridge.sol"; import "./lib/EmergencyManager.sol"; import "./interfaces/IPolygonZkEVMErrors.sol"; /** * Contract responsible for managing the states and the updates of L2 network. * There will be a trusted sequencer, which is able to send transactions. * Any user can force some transaction and the sequencer will have a timeout to add them in the queue. * The sequenced state is deterministic and can be precalculated before it's actually verified by a zkProof. * The aggregators will be able to verify the sequenced state with zkProofs and therefore make available the withdrawals from L2 network. * To enter and exit of the L2 network will be used a PolygonZkEVMBridge smart contract that will be deployed in both networks. */ contract PolygonZkEVM is OwnableUpgradeable, EmergencyManager, IPolygonZkEVMErrors { using SafeERC20Upgradeable for IERC20Upgradeable; /** * @notice Struct which will be used to call sequenceBatches * @param transactions L2 ethereum transactions EIP-155 or pre-EIP-155 with signature: * EIP-155: rlp(nonce, gasprice, gasLimit, to, value, data, chainid, 0, 0,) || v || r || s * pre-EIP-155: rlp(nonce, gasprice, gasLimit, to, value, data) || v || r || s * @param globalExitRoot Global exit root of the batch * @param timestamp Sequenced timestamp of the batch * @param minForcedTimestamp Minimum timestamp of the force batch data, empty when non forced batch */ struct BatchData { bytes transactions; bytes32 globalExitRoot; uint64 timestamp; uint64 minForcedTimestamp; } /** * @notice Struct which will be used to call sequenceForceBatches * @param transactions L2 ethereum transactions EIP-155 or pre-EIP-155 with signature: * EIP-155: rlp(nonce, gasprice, gasLimit, to, value, data, chainid, 0, 0,) || v || r || s * pre-EIP-155: rlp(nonce, gasprice, gasLimit, to, value, data) || v || r || s * @param globalExitRoot Global exit root of the batch * @param minForcedTimestamp Indicates the minimum sequenced timestamp of the batch */ struct ForcedBatchData { bytes transactions; bytes32 globalExitRoot; uint64 minForcedTimestamp; } /** * @notice Struct which will be stored for every batch sequence * @param accInputHash Hash chain that contains all the information to process a batch: * keccak256(bytes32 oldAccInputHash, keccak256(bytes transactions), bytes32 globalExitRoot, uint64 timestamp, address seqAddress) * @param sequencedTimestamp Sequenced timestamp * @param previousLastBatchSequenced Previous last batch sequenced before the current one, this is used to properly calculate the fees */ struct SequencedBatchData { bytes32 accInputHash; uint64 sequencedTimestamp; uint64 previousLastBatchSequenced; } /** * @notice Struct to store the pending states * Pending state will be an intermediary state, that after a timeout can be consolidated, which means that will be added * to the state root mapping, and the global exit root will be updated * This is a protection mechanism against soundness attacks, that will be turned off in the future * @param timestamp Timestamp where the pending state is added to the queue * @param lastVerifiedBatch Last batch verified batch of this pending state * @param exitRoot Pending exit root * @param stateRoot Pending state root */ struct PendingState { uint64 timestamp; uint64 lastVerifiedBatch; bytes32 exitRoot; bytes32 stateRoot; } /** * @notice Struct to call initialize, this saves gas because pack the parameters and avoid stack too deep errors. * @param admin Admin address * @param trustedSequencer Trusted sequencer address * @param pendingStateTimeout Pending state timeout * @param trustedAggregator Trusted aggregator * @param trustedAggregatorTimeout Trusted aggregator timeout */ struct InitializePackedParameters { address admin; address trustedSequencer; uint64 pendingStateTimeout; address trustedAggregator; uint64 trustedAggregatorTimeout; } // Modulus zkSNARK uint256 internal constant _RFIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617; // Max transactions bytes that can be added in a single batch // Max keccaks circuit = (2**23 / 155286) * 44 = 2376 // Bytes per keccak = 136 // Minimum Static keccaks batch = 2 // Max bytes allowed = (2376 - 2) * 136 = 322864 bytes - 1 byte padding // Rounded to 300000 bytes // In order to process the transaction, the data is approximately hashed twice for ecrecover: // 300000 bytes / 2 = 150000 bytes // Since geth pool currently only accepts at maximum 128kb transactions: // https://github.com/ethereum/go-ethereum/blob/master/core/txpool/txpool.go#L54 // We will limit this length to be compliant with the geth restrictions since our node will use it // We let 8kb as a sanity margin uint256 internal constant _MAX_TRANSACTIONS_BYTE_LENGTH = 120000; // Max force batch transaction length // This is used to avoid huge calldata attacks, where the attacker call force batches from another contract uint256 internal constant _MAX_FORCE_BATCH_BYTE_LENGTH = 5000; // If a sequenced batch exceeds this timeout without being verified, the contract enters in emergency mode uint64 internal constant _HALT_AGGREGATION_TIMEOUT = 1 weeks; // Maximum batches that can be verified in one call. It depends on our current metrics // This should be a protection against someone that tries to generate huge chunk of invalid batches, and we can't prove otherwise before the pending timeout expires uint64 internal constant _MAX_VERIFY_BATCHES = 1000; // Max batch multiplier per verification uint256 internal constant _MAX_BATCH_MULTIPLIER = 12; // Max batch fee value uint256 internal constant _MAX_BATCH_FEE = 1000 ether; // Min value batch fee uint256 internal constant _MIN_BATCH_FEE = 1 gwei; // Goldilocks prime field uint256 internal constant _GOLDILOCKS_PRIME_FIELD = 0xFFFFFFFF00000001; // 2 ** 64 - 2 ** 32 + 1 // Max uint64 uint256 internal constant _MAX_UINT_64 = type(uint64).max; // 0xFFFFFFFFFFFFFFFF // MATIC token address IERC20Upgradeable public immutable matic; // Rollup verifier interface IVerifierRollup public immutable rollupVerifier; // Global Exit Root interface IPolygonZkEVMGlobalExitRoot public immutable globalExitRootManager; // PolygonZkEVM Bridge Address IPolygonZkEVMBridge public immutable bridgeAddress; // L2 chain identifier uint64 public immutable chainID; // L2 chain identifier uint64 public immutable forkID; // Time target of the verification of a batch // Adaptatly the batchFee will be updated to achieve this target uint64 public verifyBatchTimeTarget; // Batch fee multiplier with 3 decimals that goes from 1000 - 1023 uint16 public multiplierBatchFee; // Trusted sequencer address address public trustedSequencer; // Current matic fee per batch sequenced uint256 public batchFee; // Queue of forced batches with their associated data // ForceBatchNum --> hashedForcedBatchData // hashedForcedBatchData: hash containing the necessary information to force a batch: // keccak256(keccak256(bytes transactions), bytes32 globalExitRoot, unint64 minForcedTimestamp) mapping(uint64 => bytes32) public forcedBatches; // Queue of batches that defines the virtual state // SequenceBatchNum --> SequencedBatchData mapping(uint64 => SequencedBatchData) public sequencedBatches; // Last sequenced timestamp uint64 public lastTimestamp; // Last batch sent by the sequencers uint64 public lastBatchSequenced; // Last forced batch included in the sequence uint64 public lastForceBatchSequenced; // Last forced batch uint64 public lastForceBatch; // Last batch verified by the aggregators uint64 public lastVerifiedBatch; // Trusted aggregator address address public trustedAggregator; // State root mapping // BatchNum --> state root mapping(uint64 => bytes32) public batchNumToStateRoot; // Trusted sequencer URL string public trustedSequencerURL; // L2 network name string public networkName; // Pending state mapping // pendingStateNumber --> PendingState mapping(uint256 => PendingState) public pendingStateTransitions; // Last pending state uint64 public lastPendingState; // Last pending state consolidated uint64 public lastPendingStateConsolidated; // Once a pending state exceeds this timeout it can be consolidated uint64 public pendingStateTimeout; // Trusted aggregator timeout, if a sequence is not verified in this time frame, // everyone can verify that sequence uint64 public trustedAggregatorTimeout; // Address that will be able to adjust contract parameters or stop the emergency state address public admin; // This account will be able to accept the admin role address public pendingAdmin; // Force batch timeout uint64 public forceBatchTimeout; // Indicates if forced batches are disallowed bool public isForcedBatchDisallowed; /** * @dev Emitted when the trusted sequencer sends a new batch of transactions */ event SequenceBatches(uint64 indexed numBatch); /** * @dev Emitted when a batch is forced */ event ForceBatch( uint64 indexed forceBatchNum, bytes32 lastGlobalExitRoot, address sequencer, bytes transactions ); /** * @dev Emitted when forced batches are sequenced by not the trusted sequencer */ event SequenceForceBatches(uint64 indexed numBatch); /** * @dev Emitted when a aggregator verifies batches */ event VerifyBatches( uint64 indexed numBatch, bytes32 stateRoot, address indexed aggregator ); /** * @dev Emitted when the trusted aggregator verifies batches */ event VerifyBatchesTrustedAggregator( uint64 indexed numBatch, bytes32 stateRoot, address indexed aggregator ); /** * @dev Emitted when pending state is consolidated */ event ConsolidatePendingState( uint64 indexed numBatch, bytes32 stateRoot, uint64 indexed pendingStateNum ); /** * @dev Emitted when the admin updates the trusted sequencer address */ event SetTrustedSequencer(address newTrustedSequencer); /** * @dev Emitted when the admin updates the sequencer URL */ event SetTrustedSequencerURL(string newTrustedSequencerURL); /** * @dev Emitted when the admin updates the trusted aggregator timeout */ event SetTrustedAggregatorTimeout(uint64 newTrustedAggregatorTimeout); /** * @dev Emitted when the admin updates the pending state timeout */ event SetPendingStateTimeout(uint64 newPendingStateTimeout); /** * @dev Emitted when the admin updates the trusted aggregator address */ event SetTrustedAggregator(address newTrustedAggregator); /** * @dev Emitted when the admin updates the multiplier batch fee */ event SetMultiplierBatchFee(uint16 newMultiplierBatchFee); /** * @dev Emitted when the admin updates the verify batch timeout */ event SetVerifyBatchTimeTarget(uint64 newVerifyBatchTimeTarget); /** * @dev Emitted when the admin update the force batch timeout */ event SetForceBatchTimeout(uint64 newforceBatchTimeout); /** * @dev Emitted when activate force batches */ event ActivateForceBatches(); /** * @dev Emitted when the admin starts the two-step transfer role setting a new pending admin */ event TransferAdminRole(address newPendingAdmin); /** * @dev Emitted when the pending admin accepts the admin role */ event AcceptAdminRole(address newAdmin); /** * @dev Emitted when is proved a different state given the same batches */ event ProveNonDeterministicPendingState( bytes32 storedStateRoot, bytes32 provedStateRoot ); /** * @dev Emitted when the trusted aggregator overrides pending state */ event OverridePendingState( uint64 indexed numBatch, bytes32 stateRoot, address indexed aggregator ); /** * @dev Emitted everytime the forkID is updated, this includes the first initialization of the contract * This event is intended to be emitted for every upgrade of the contract with relevant changes for the nodes */ event UpdateZkEVMVersion(uint64 numBatch, uint64 forkID, string version); /** * @param _globalExitRootManager Global exit root manager address * @param _matic MATIC token address * @param _rollupVerifier Rollup verifier address * @param _bridgeAddress Bridge address * @param _chainID L2 chainID * @param _forkID Fork Id */ constructor( IPolygonZkEVMGlobalExitRoot _globalExitRootManager, IERC20Upgradeable _matic, IVerifierRollup _rollupVerifier, IPolygonZkEVMBridge _bridgeAddress, uint64 _chainID, uint64 _forkID ) { globalExitRootManager = _globalExitRootManager; matic = _matic; rollupVerifier = _rollupVerifier; bridgeAddress = _bridgeAddress; chainID = _chainID; forkID = _forkID; } /** * @param initializePackedParameters Struct to save gas and avoid stack too deep errors * @param genesisRoot Rollup genesis root * @param _trustedSequencerURL Trusted sequencer URL * @param _networkName L2 network name */ function initialize( InitializePackedParameters calldata initializePackedParameters, bytes32 genesisRoot, string memory _trustedSequencerURL, string memory _networkName, string calldata _version ) external initializer { admin = initializePackedParameters.admin; trustedSequencer = initializePackedParameters.trustedSequencer; trustedAggregator = initializePackedParameters.trustedAggregator; batchNumToStateRoot[0] = genesisRoot; trustedSequencerURL = _trustedSequencerURL; networkName = _networkName; // Check initialize parameters if ( initializePackedParameters.pendingStateTimeout > _HALT_AGGREGATION_TIMEOUT ) { revert PendingStateTimeoutExceedHaltAggregationTimeout(); } pendingStateTimeout = initializePackedParameters.pendingStateTimeout; if ( initializePackedParameters.trustedAggregatorTimeout > _HALT_AGGREGATION_TIMEOUT ) { revert TrustedAggregatorTimeoutExceedHaltAggregationTimeout(); } trustedAggregatorTimeout = initializePackedParameters .trustedAggregatorTimeout; // Constant deployment variables batchFee = 0.1 ether; // 0.1 Matic verifyBatchTimeTarget = 30 minutes; multiplierBatchFee = 1002; forceBatchTimeout = 5 days; isForcedBatchDisallowed = true; // Initialize OZ contracts __Ownable_init_unchained(); // emit version event emit UpdateZkEVMVersion(0, forkID, _version); } modifier onlyAdmin() { if (admin != msg.sender) { revert OnlyAdmin(); } _; } modifier onlyTrustedSequencer() { if (trustedSequencer != msg.sender) { revert OnlyTrustedSequencer(); } _; } modifier onlyTrustedAggregator() { if (trustedAggregator != msg.sender) { revert OnlyTrustedAggregator(); } _; } modifier isForceBatchAllowed() { if (isForcedBatchDisallowed) { revert ForceBatchNotAllowed(); } _; } ///////////////////////////////////// // Sequence/Verify batches functions //////////////////////////////////// /** * @notice Allows a sequencer to send multiple batches * @param batches Struct array which holds the necessary data to append new batches to the sequence * @param l2Coinbase Address that will receive the fees from L2 */ function sequenceBatches( BatchData[] calldata batches, address l2Coinbase ) external ifNotEmergencyState onlyTrustedSequencer { uint256 batchesNum = batches.length; if (batchesNum == 0) { revert SequenceZeroBatches(); } if (batchesNum > _MAX_VERIFY_BATCHES) { revert ExceedMaxVerifyBatches(); } // Store storage variables in memory, to save gas, because will be overrided multiple times uint64 currentTimestamp = lastTimestamp; uint64 currentBatchSequenced = lastBatchSequenced; uint64 currentLastForceBatchSequenced = lastForceBatchSequenced; bytes32 currentAccInputHash = sequencedBatches[currentBatchSequenced] .accInputHash; // Store in a temporal variable, for avoid access again the storage slot uint64 initLastForceBatchSequenced = currentLastForceBatchSequenced; for (uint256 i = 0; i < batchesNum; i++) { // Load current sequence BatchData memory currentBatch = batches[i]; // Store the current transactions hash since can be used more than once for gas saving bytes32 currentTransactionsHash = keccak256( currentBatch.transactions ); // Check if it's a forced batch if (currentBatch.minForcedTimestamp > 0) { currentLastForceBatchSequenced++; // Check forced data matches bytes32 hashedForcedBatchData = keccak256( abi.encodePacked( currentTransactionsHash, currentBatch.globalExitRoot, currentBatch.minForcedTimestamp ) ); if ( hashedForcedBatchData != forcedBatches[currentLastForceBatchSequenced] ) { revert ForcedDataDoesNotMatch(); } // Delete forceBatch data since won't be used anymore delete forcedBatches[currentLastForceBatchSequenced]; // Check timestamp is bigger than min timestamp if (currentBatch.timestamp < currentBatch.minForcedTimestamp) { revert SequencedTimestampBelowForcedTimestamp(); } } else { // Check global exit root exists with proper batch length. These checks are already done in the forceBatches call // Note that the sequencer can skip setting a global exit root putting zeros if ( currentBatch.globalExitRoot != bytes32(0) && globalExitRootManager.globalExitRootMap( currentBatch.globalExitRoot ) == 0 ) { revert GlobalExitRootNotExist(); } if ( currentBatch.transactions.length > _MAX_TRANSACTIONS_BYTE_LENGTH ) { revert TransactionsLengthAboveMax(); } } // Check Batch timestamps are correct if ( currentBatch.timestamp < currentTimestamp || currentBatch.timestamp > block.timestamp ) { revert SequencedTimestampInvalid(); } // Calculate next accumulated input hash currentAccInputHash = keccak256( abi.encodePacked( currentAccInputHash, currentTransactionsHash, currentBatch.globalExitRoot, currentBatch.timestamp, l2Coinbase ) ); // Update timestamp currentTimestamp = currentBatch.timestamp; } // Update currentBatchSequenced currentBatchSequenced += uint64(batchesNum); // Sanity check, should be unreachable if (currentLastForceBatchSequenced > lastForceBatch) { revert ForceBatchesOverflow(); } uint256 nonForcedBatchesSequenced = batchesNum - (currentLastForceBatchSequenced - initLastForceBatchSequenced); // Update sequencedBatches mapping sequencedBatches[currentBatchSequenced] = SequencedBatchData({ accInputHash: currentAccInputHash, sequencedTimestamp: uint64(block.timestamp), previousLastBatchSequenced: lastBatchSequenced }); // Store back the storage variables lastTimestamp = currentTimestamp; lastBatchSequenced = currentBatchSequenced; if (currentLastForceBatchSequenced != initLastForceBatchSequenced) lastForceBatchSequenced = currentLastForceBatchSequenced; // Pay collateral for every non-forced batch submitted matic.safeTransferFrom( msg.sender, address(this), batchFee * nonForcedBatchesSequenced ); // Consolidate pending state if possible _tryConsolidatePendingState(); // Update global exit root if there are new deposits bridgeAddress.updateGlobalExitRoot(); emit SequenceBatches(currentBatchSequenced); } /** * @notice Allows an aggregator to verify multiple batches * @param pendingStateNum Init pending state, 0 if consolidated state is used * @param initNumBatch Batch which the aggregator starts the verification * @param finalNewBatch Last batch aggregator intends to verify * @param newLocalExitRoot New local exit root once the batch is processed * @param newStateRoot New State root once the batch is processed * @param proof fflonk proof */ function verifyBatches( uint64 pendingStateNum, uint64 initNumBatch, uint64 finalNewBatch, bytes32 newLocalExitRoot, bytes32 newStateRoot, bytes32[24] calldata proof ) external ifNotEmergencyState { // Check if the trusted aggregator timeout expired, // Note that the sequencedBatches struct must exists for this finalNewBatch, if not newAccInputHash will be 0 if ( sequencedBatches[finalNewBatch].sequencedTimestamp + trustedAggregatorTimeout > block.timestamp ) { revert TrustedAggregatorTimeoutNotExpired(); } if (finalNewBatch - initNumBatch > _MAX_VERIFY_BATCHES) { revert ExceedMaxVerifyBatches(); } _verifyAndRewardBatches( pendingStateNum, initNumBatch, finalNewBatch, newLocalExitRoot, newStateRoot, proof ); // Update batch fees _updateBatchFee(finalNewBatch); if (pendingStateTimeout == 0) { // Consolidate state lastVerifiedBatch = finalNewBatch; batchNumToStateRoot[finalNewBatch] = newStateRoot; // Clean pending state if any if (lastPendingState > 0) { lastPendingState = 0; lastPendingStateConsolidated = 0; } // Interact with globalExitRootManager globalExitRootManager.updateExitRoot(newLocalExitRoot); } else { // Consolidate pending state if possible _tryConsolidatePendingState(); // Update pending state lastPendingState++; pendingStateTransitions[lastPendingState] = PendingState({ timestamp: uint64(block.timestamp), lastVerifiedBatch: finalNewBatch, exitRoot: newLocalExitRoot, stateRoot: newStateRoot }); } emit VerifyBatches(finalNewBatch, newStateRoot, msg.sender); } /** * @notice Allows an aggregator to verify multiple batches * @param pendingStateNum Init pending state, 0 if consolidated state is used * @param initNumBatch Batch which the aggregator starts the verification * @param finalNewBatch Last batch aggregator intends to verify * @param newLocalExitRoot New local exit root once the batch is processed * @param newStateRoot New State root once the batch is processed * @param proof fflonk proof */ function verifyBatchesTrustedAggregator( uint64 pendingStateNum, uint64 initNumBatch, uint64 finalNewBatch, bytes32 newLocalExitRoot, bytes32 newStateRoot, bytes32[24] calldata proof ) external onlyTrustedAggregator { _verifyAndRewardBatches( pendingStateNum, initNumBatch, finalNewBatch, newLocalExitRoot, newStateRoot, proof ); // Consolidate state lastVerifiedBatch = finalNewBatch; batchNumToStateRoot[finalNewBatch] = newStateRoot; // Clean pending state if any if (lastPendingState > 0) { lastPendingState = 0; lastPendingStateConsolidated = 0; } // Interact with globalExitRootManager globalExitRootManager.updateExitRoot(newLocalExitRoot); emit VerifyBatchesTrustedAggregator( finalNewBatch, newStateRoot, msg.sender ); } /** * @notice Verify and reward batches internal function * @param pendingStateNum Init pending state, 0 if consolidated state is used * @param initNumBatch Batch which the aggregator starts the verification * @param finalNewBatch Last batch aggregator intends to verify * @param newLocalExitRoot New local exit root once the batch is processed * @param newStateRoot New State root once the batch is processed * @param proof fflonk proof */ function _verifyAndRewardBatches( uint64 pendingStateNum, uint64 initNumBatch, uint64 finalNewBatch, bytes32 newLocalExitRoot, bytes32 newStateRoot, bytes32[24] calldata proof ) internal virtual { bytes32 oldStateRoot; uint64 currentLastVerifiedBatch = getLastVerifiedBatch(); // Use pending state if specified, otherwise use consolidated state if (pendingStateNum != 0) { // Check that pending state exist // Already consolidated pending states can be used aswell if (pendingStateNum > lastPendingState) { revert PendingStateDoesNotExist(); } // Check choosen pending state PendingState storage currentPendingState = pendingStateTransitions[ pendingStateNum ]; // Get oldStateRoot from pending batch oldStateRoot = currentPendingState.stateRoot; // Check initNumBatch matches the pending state if (initNumBatch != currentPendingState.lastVerifiedBatch) { revert InitNumBatchDoesNotMatchPendingState(); } } else { // Use consolidated state oldStateRoot = batchNumToStateRoot[initNumBatch]; if (oldStateRoot == bytes32(0)) { revert OldStateRootDoesNotExist(); } // Check initNumBatch is inside the range, sanity check if (initNumBatch > currentLastVerifiedBatch) { revert InitNumBatchAboveLastVerifiedBatch(); } } // Check final batch if (finalNewBatch <= currentLastVerifiedBatch) { revert FinalNumBatchBelowLastVerifiedBatch(); } // Get snark bytes bytes memory snarkHashBytes = getInputSnarkBytes( initNumBatch, finalNewBatch, newLocalExitRoot, oldStateRoot, newStateRoot ); // Calulate the snark input uint256 inputSnark = uint256(sha256(snarkHashBytes)) % _RFIELD; // Verify proof if (!rollupVerifier.verifyProof(proof, [inputSnark])) { revert InvalidProof(); } // Get MATIC reward matic.safeTransfer( msg.sender, calculateRewardPerBatch() * (finalNewBatch - currentLastVerifiedBatch) ); } /** * @notice Internal function to consolidate the state automatically once sequence or verify batches are called * It tries to consolidate the first and the middle pending state in the queue */ function _tryConsolidatePendingState() internal { // Check if there's any state to consolidate if (lastPendingState > lastPendingStateConsolidated) { // Check if it's possible to consolidate the next pending state uint64 nextPendingState = lastPendingStateConsolidated + 1; if (isPendingStateConsolidable(nextPendingState)) { // Check middle pending state ( binary search of 1 step) uint64 middlePendingState = nextPendingState + (lastPendingState - nextPendingState) / 2; // Try to consolidate it, and if not, consolidate the nextPendingState if (isPendingStateConsolidable(middlePendingState)) { _consolidatePendingState(middlePendingState); } else { _consolidatePendingState(nextPendingState); } } } } /** * @notice Allows to consolidate any pending state that has already exceed the pendingStateTimeout * Can be called by the trusted aggregator, which can consolidate any state without the timeout restrictions * @param pendingStateNum Pending state to consolidate */ function consolidatePendingState(uint64 pendingStateNum) external { // Check if pending state can be consolidated // If trusted aggregator is the sender, do not check the timeout or the emergency state if (msg.sender != trustedAggregator) { if (isEmergencyState) { revert OnlyNotEmergencyState(); } if (!isPendingStateConsolidable(pendingStateNum)) { revert PendingStateNotConsolidable(); } } _consolidatePendingState(pendingStateNum); } /** * @notice Internal function to consolidate any pending state that has already exceed the pendingStateTimeout * @param pendingStateNum Pending state to consolidate */ function _consolidatePendingState(uint64 pendingStateNum) internal { // Check if pendingStateNum is in correct range // - not consolidated (implicity checks that is not 0) // - exist ( has been added) if ( pendingStateNum <= lastPendingStateConsolidated || pendingStateNum > lastPendingState ) { revert PendingStateInvalid(); } PendingState storage currentPendingState = pendingStateTransitions[ pendingStateNum ]; // Update state uint64 newLastVerifiedBatch = currentPendingState.lastVerifiedBatch; lastVerifiedBatch = newLastVerifiedBatch; batchNumToStateRoot[newLastVerifiedBatch] = currentPendingState .stateRoot; // Update pending state lastPendingStateConsolidated = pendingStateNum; // Interact with globalExitRootManager globalExitRootManager.updateExitRoot(currentPendingState.exitRoot); emit ConsolidatePendingState( newLastVerifiedBatch, currentPendingState.stateRoot, pendingStateNum ); } /** * @notice Function to update the batch fee based on the new verified batches * The batch fee will not be updated when the trusted aggregator verifies batches * @param newLastVerifiedBatch New last verified batch */ function _updateBatchFee(uint64 newLastVerifiedBatch) internal { uint64 currentLastVerifiedBatch = getLastVerifiedBatch(); uint64 currentBatch = newLastVerifiedBatch; uint256 totalBatchesAboveTarget; uint256 newBatchesVerified = newLastVerifiedBatch - currentLastVerifiedBatch; uint256 targetTimestamp = block.timestamp - verifyBatchTimeTarget; while (currentBatch != currentLastVerifiedBatch) { // Load sequenced batchdata SequencedBatchData storage currentSequencedBatchData = sequencedBatches[ currentBatch ]; // Check if timestamp is below the verifyBatchTimeTarget if ( targetTimestamp < currentSequencedBatchData.sequencedTimestamp ) { // update currentBatch currentBatch = currentSequencedBatchData .previousLastBatchSequenced; } else { // The rest of batches will be above totalBatchesAboveTarget = currentBatch - currentLastVerifiedBatch; break; } } uint256 totalBatchesBelowTarget = newBatchesVerified - totalBatchesAboveTarget; // _MAX_BATCH_FEE --> (< 70 bits) // multiplierBatchFee --> (< 10 bits) // _MAX_BATCH_MULTIPLIER = 12 // multiplierBatchFee ** _MAX_BATCH_MULTIPLIER --> (< 128 bits) // batchFee * (multiplierBatchFee ** _MAX_BATCH_MULTIPLIER)--> // (< 70 bits) * (< 128 bits) = < 256 bits // Since all the following operations cannot overflow, we can optimize this operations with unchecked unchecked { if (totalBatchesBelowTarget < totalBatchesAboveTarget) { // There are more batches above target, fee is multiplied uint256 diffBatches = totalBatchesAboveTarget - totalBatchesBelowTarget; diffBatches = diffBatches > _MAX_BATCH_MULTIPLIER ? _MAX_BATCH_MULTIPLIER : diffBatches; // For every multiplierBatchFee multiplication we must shift 3 zeroes since we have 3 decimals batchFee = (batchFee * (uint256(multiplierBatchFee) ** diffBatches)) / (uint256(1000) ** diffBatches); } else { // There are more batches below target, fee is divided uint256 diffBatches = totalBatchesBelowTarget - totalBatchesAboveTarget; diffBatches = diffBatches > _MAX_BATCH_MULTIPLIER ? _MAX_BATCH_MULTIPLIER : diffBatches; // For every multiplierBatchFee multiplication we must shift 3 zeroes since we have 3 decimals uint256 accDivisor = (uint256(1 ether) * (uint256(multiplierBatchFee) ** diffBatches)) / (uint256(1000) ** diffBatches); // multiplyFactor = multiplierBatchFee ** diffBatches / 10 ** (diffBatches * 3) // accDivisor = 1E18 * multiplyFactor // 1E18 * batchFee / accDivisor = batchFee / multiplyFactor // < 60 bits * < 70 bits / ~60 bits --> overflow not possible batchFee = (uint256(1 ether) * batchFee) / accDivisor; } } // Batch fee must remain inside a range if (batchFee > _MAX_BATCH_FEE) { batchFee = _MAX_BATCH_FEE; } else if (batchFee < _MIN_BATCH_FEE) { batchFee = _MIN_BATCH_FEE; } } //////////////////////////// // Force batches functions //////////////////////////// /** * @notice Allows a sequencer/user to force a batch of L2 transactions. * This should be used only in extreme cases where the trusted sequencer does not work as expected * Note The sequencer has certain degree of control on how non-forced and forced batches are ordered * In order to assure that users force transactions will be processed properly, user must not sign any other transaction * with the same nonce * @param transactions L2 ethereum transactions EIP-155 or pre-EIP-155 with signature: * @param maticAmount Max amount of MATIC tokens that the sender is willing to pay */ function forceBatch( bytes calldata transactions, uint256 maticAmount ) public isForceBatchAllowed ifNotEmergencyState { // Calculate matic collateral uint256 maticFee = getForcedBatchFee(); if (maticFee > maticAmount) { revert NotEnoughMaticAmount(); } if (transactions.length > _MAX_FORCE_BATCH_BYTE_LENGTH) { revert TransactionsLengthAboveMax(); } matic.safeTransferFrom(msg.sender, address(this), maticFee); // Get globalExitRoot global exit root bytes32 lastGlobalExitRoot = globalExitRootManager .getLastGlobalExitRoot(); // Update forcedBatches mapping lastForceBatch++; forcedBatches[lastForceBatch] = keccak256( abi.encodePacked( keccak256(transactions), lastGlobalExitRoot, uint64(block.timestamp) ) ); if (msg.sender == tx.origin) { // Getting the calldata from an EOA is easy so no need to put the `transactions` in the event emit ForceBatch(lastForceBatch, lastGlobalExitRoot, msg.sender, ""); } else { // Getting internal transaction calldata is complicated (because it requires an archive node) // Therefore it's worth it to put the `transactions` in the event, which is easy to query emit ForceBatch( lastForceBatch, lastGlobalExitRoot, msg.sender, transactions ); } } /** * @notice Allows anyone to sequence forced Batches if the trusted sequencer has not done so in the timeout period * @param batches Struct array which holds the necessary data to append force batches */ function sequenceForceBatches( ForcedBatchData[] calldata batches ) external isForceBatchAllowed ifNotEmergencyState { uint256 batchesNum = batches.length; if (batchesNum == 0) { revert SequenceZeroBatches(); } if (batchesNum > _MAX_VERIFY_BATCHES) { revert ExceedMaxVerifyBatches(); } if ( uint256(lastForceBatchSequenced) + batchesNum > uint256(lastForceBatch) ) { revert ForceBatchesOverflow(); } // Store storage variables in memory, to save gas, because will be overrided multiple times uint64 currentBatchSequenced = lastBatchSequenced; uint64 currentLastForceBatchSequenced = lastForceBatchSequenced; bytes32 currentAccInputHash = sequencedBatches[currentBatchSequenced] .accInputHash; // Sequence force batches for (uint256 i = 0; i < batchesNum; i++) { // Load current sequence ForcedBatchData memory currentBatch = batches[i]; currentLastForceBatchSequenced++; // Store the current transactions hash since it's used more than once for gas saving bytes32 currentTransactionsHash = keccak256( currentBatch.transactions ); // Check forced data matches bytes32 hashedForcedBatchData = keccak256( abi.encodePacked( currentTransactionsHash, currentBatch.globalExitRoot, currentBatch.minForcedTimestamp ) ); if ( hashedForcedBatchData != forcedBatches[currentLastForceBatchSequenced] ) { revert ForcedDataDoesNotMatch(); } // Delete forceBatch data since won't be used anymore delete forcedBatches[currentLastForceBatchSequenced]; if (i == (batchesNum - 1)) { // The last batch will have the most restrictive timestamp if ( currentBatch.minForcedTimestamp + forceBatchTimeout > block.timestamp ) { revert ForceBatchTimeoutNotExpired(); } } // Calculate next acc input hash currentAccInputHash = keccak256( abi.encodePacked( currentAccInputHash, currentTransactionsHash, currentBatch.globalExitRoot, uint64(block.timestamp), msg.sender ) ); } // Update currentBatchSequenced currentBatchSequenced += uint64(batchesNum); lastTimestamp = uint64(block.timestamp); // Store back the storage variables sequencedBatches[currentBatchSequenced] = SequencedBatchData({ accInputHash: currentAccInputHash, sequencedTimestamp: uint64(block.timestamp), previousLastBatchSequenced: lastBatchSequenced }); lastBatchSequenced = currentBatchSequenced; lastForceBatchSequenced = currentLastForceBatchSequenced; emit SequenceForceBatches(currentBatchSequenced); } ////////////////// // admin functions ////////////////// /** * @notice Allow the admin to set a new trusted sequencer * @param newTrustedSequencer Address of the new trusted sequencer */ function setTrustedSequencer( address newTrustedSequencer ) external onlyAdmin { trustedSequencer = newTrustedSequencer; emit SetTrustedSequencer(newTrustedSequencer); } /** * @notice Allow the admin to set the trusted sequencer URL * @param newTrustedSequencerURL URL of trusted sequencer */ function setTrustedSequencerURL( string memory newTrustedSequencerURL ) external onlyAdmin { trustedSequencerURL = newTrustedSequencerURL; emit SetTrustedSequencerURL(newTrustedSequencerURL); } /** * @notice Allow the admin to set a new trusted aggregator address * @param newTrustedAggregator Address of the new trusted aggregator */ function setTrustedAggregator( address newTrustedAggregator ) external onlyAdmin { trustedAggregator = newTrustedAggregator; emit SetTrustedAggregator(newTrustedAggregator); } /** * @notice Allow the admin to set a new pending state timeout * The timeout can only be lowered, except if emergency state is active * @param newTrustedAggregatorTimeout Trusted aggregator timeout */ function setTrustedAggregatorTimeout( uint64 newTrustedAggregatorTimeout ) external onlyAdmin { if (newTrustedAggregatorTimeout > _HALT_AGGREGATION_TIMEOUT) { revert TrustedAggregatorTimeoutExceedHaltAggregationTimeout(); } if (!isEmergencyState) { if (newTrustedAggregatorTimeout >= trustedAggregatorTimeout) { revert NewTrustedAggregatorTimeoutMustBeLower(); } } trustedAggregatorTimeout = newTrustedAggregatorTimeout; emit SetTrustedAggregatorTimeout(newTrustedAggregatorTimeout); } /** * @notice Allow the admin to set a new trusted aggregator timeout * The timeout can only be lowered, except if emergency state is active * @param newPendingStateTimeout Trusted aggregator timeout */ function setPendingStateTimeout( uint64 newPendingStateTimeout ) external onlyAdmin { if (newPendingStateTimeout > _HALT_AGGREGATION_TIMEOUT) { revert PendingStateTimeoutExceedHaltAggregationTimeout(); } if (!isEmergencyState) { if (newPendingStateTimeout >= pendingStateTimeout) { revert NewPendingStateTimeoutMustBeLower(); } } pendingStateTimeout = newPendingStateTimeout; emit SetPendingStateTimeout(newPendingStateTimeout); } /** * @notice Allow the admin to set a new multiplier batch fee * @param newMultiplierBatchFee multiplier batch fee */ function setMultiplierBatchFee( uint16 newMultiplierBatchFee ) external onlyAdmin { if (newMultiplierBatchFee < 1000 || newMultiplierBatchFee > 1023) { revert InvalidRangeMultiplierBatchFee(); } multiplierBatchFee = newMultiplierBatchFee; emit SetMultiplierBatchFee(newMultiplierBatchFee); } /** * @notice Allow the admin to set a new verify batch time target * This value will only be relevant once the aggregation is decentralized, so * the trustedAggregatorTimeout should be zero or very close to zero * @param newVerifyBatchTimeTarget Verify batch time target */ function setVerifyBatchTimeTarget( uint64 newVerifyBatchTimeTarget ) external onlyAdmin { if (newVerifyBatchTimeTarget > 1 days) { revert InvalidRangeBatchTimeTarget(); } verifyBatchTimeTarget = newVerifyBatchTimeTarget; emit SetVerifyBatchTimeTarget(newVerifyBatchTimeTarget); } /** * @notice Allow the admin to set the forcedBatchTimeout * The new value can only be lower, except if emergency state is active * @param newforceBatchTimeout New force batch timeout */ function setForceBatchTimeout( uint64 newforceBatchTimeout ) external onlyAdmin { if (newforceBatchTimeout > _HALT_AGGREGATION_TIMEOUT) { revert InvalidRangeForceBatchTimeout(); } if (!isEmergencyState) { if (newforceBatchTimeout >= forceBatchTimeout) { revert InvalidRangeForceBatchTimeout(); } } forceBatchTimeout = newforceBatchTimeout; emit SetForceBatchTimeout(newforceBatchTimeout); } /** * @notice Allow the admin to turn on the force batches * This action is not reversible */ function activateForceBatches() external onlyAdmin { if (!isForcedBatchDisallowed) { revert ForceBatchesAlreadyActive(); } isForcedBatchDisallowed = false; emit ActivateForceBatches(); } /** * @notice Starts the admin role transfer * This is a two step process, the pending admin must accepted to finalize the process * @param newPendingAdmin Address of the new pending admin */ function transferAdminRole(address newPendingAdmin) external onlyAdmin { pendingAdmin = newPendingAdmin; emit TransferAdminRole(newPendingAdmin); } /** * @notice Allow the current pending admin to accept the admin role */ function acceptAdminRole() external { if (pendingAdmin != msg.sender) { revert OnlyPendingAdmin(); } admin = pendingAdmin; emit AcceptAdminRole(pendingAdmin); } ///////////////////////////////// // Soundness protection functions ///////////////////////////////// /** * @notice Allows the trusted aggregator to override the pending state * if it's possible to prove a different state root given the same batches * @param initPendingStateNum Init pending state, 0 if consolidated state is used * @param finalPendingStateNum Final pending state, that will be used to compare with the newStateRoot * @param initNumBatch Batch which the aggregator starts the verification * @param finalNewBatch Last batch aggregator intends to verify * @param newLocalExitRoot New local exit root once the batch is processed * @param newStateRoot New State root once the batch is processed * @param proof fflonk proof */ function overridePendingState( uint64 initPendingStateNum, uint64 finalPendingStateNum, uint64 initNumBatch, uint64 finalNewBatch, bytes32 newLocalExitRoot, bytes32 newStateRoot, bytes32[24] calldata proof ) external onlyTrustedAggregator { _proveDistinctPendingState( initPendingStateNum, finalPendingStateNum, initNumBatch, finalNewBatch, newLocalExitRoot, newStateRoot, proof ); // Consolidate state state lastVerifiedBatch = finalNewBatch; batchNumToStateRoot[finalNewBatch] = newStateRoot; // Clean pending state if any if (lastPendingState > 0) { lastPendingState = 0; lastPendingStateConsolidated = 0; } // Interact with globalExitRootManager globalExitRootManager.updateExitRoot(newLocalExitRoot); // Update trusted aggregator timeout to max trustedAggregatorTimeout = _HALT_AGGREGATION_TIMEOUT; emit OverridePendingState(finalNewBatch, newStateRoot, msg.sender); } /** * @notice Allows to halt the PolygonZkEVM if its possible to prove a different state root given the same batches * @param initPendingStateNum Init pending state, 0 if consolidated state is used * @param finalPendingStateNum Final pending state, that will be used to compare with the newStateRoot * @param initNumBatch Batch which the aggregator starts the verification * @param finalNewBatch Last batch aggregator intends to verify * @param newLocalExitRoot New local exit root once the batch is processed * @param newStateRoot New State root once the batch is processed * @param proof fflonk proof */ function proveNonDeterministicPendingState( uint64 initPendingStateNum, uint64 finalPendingStateNum, uint64 initNumBatch, uint64 finalNewBatch, bytes32 newLocalExitRoot, bytes32 newStateRoot, bytes32[24] calldata proof ) external ifNotEmergencyState { _proveDistinctPendingState( initPendingStateNum, finalPendingStateNum, initNumBatch, finalNewBatch, newLocalExitRoot, newStateRoot, proof ); emit ProveNonDeterministicPendingState( batchNumToStateRoot[finalNewBatch], newStateRoot ); // Activate emergency state _activateEmergencyState(); } /** * @notice Internal function that proves a different state root given the same batches to verify * @param initPendingStateNum Init pending state, 0 if consolidated state is used * @param finalPendingStateNum Final pending state, that will be used to compare with the newStateRoot * @param initNumBatch Batch which the aggregator starts the verification * @param finalNewBatch Last batch aggregator intends to verify * @param newLocalExitRoot New local exit root once the batch is processed * @param newStateRoot New State root once the batch is processed * @param proof fflonk proof */ function _proveDistinctPendingState( uint64 initPendingStateNum, uint64 finalPendingStateNum, uint64 initNumBatch, uint64 finalNewBatch, bytes32 newLocalExitRoot, bytes32 newStateRoot, bytes32[24] calldata proof ) internal view virtual { bytes32 oldStateRoot; // Use pending state if specified, otherwise use consolidated state if (initPendingStateNum != 0) { // Check that pending state exist // Already consolidated pending states can be used aswell if (initPendingStateNum > lastPendingState) { revert PendingStateDoesNotExist(); } // Check choosen pending state PendingState storage initPendingState = pendingStateTransitions[ initPendingStateNum ]; // Get oldStateRoot from init pending state oldStateRoot = initPendingState.stateRoot; // Check initNumBatch matches the init pending state if (initNumBatch != initPendingState.lastVerifiedBatch) { revert InitNumBatchDoesNotMatchPendingState(); } } else { // Use consolidated state oldStateRoot = batchNumToStateRoot[initNumBatch]; if (oldStateRoot == bytes32(0)) { revert OldStateRootDoesNotExist(); } // Check initNumBatch is inside the range, sanity check if (initNumBatch > lastVerifiedBatch) { revert InitNumBatchAboveLastVerifiedBatch(); } } // Assert final pending state num is in correct range // - exist ( has been added) // - bigger than the initPendingstate // - not consolidated if ( finalPendingStateNum > lastPendingState || finalPendingStateNum <= initPendingStateNum || finalPendingStateNum <= lastPendingStateConsolidated ) { revert FinalPendingStateNumInvalid(); } // Check final num batch if ( finalNewBatch != pendingStateTransitions[finalPendingStateNum].lastVerifiedBatch ) { revert FinalNumBatchDoesNotMatchPendingState(); } // Get snark bytes bytes memory snarkHashBytes = getInputSnarkBytes( initNumBatch, finalNewBatch, newLocalExitRoot, oldStateRoot, newStateRoot ); // Calulate the snark input uint256 inputSnark = uint256(sha256(snarkHashBytes)) % _RFIELD; // Verify proof if (!rollupVerifier.verifyProof(proof, [inputSnark])) { revert InvalidProof(); } if ( pendingStateTransitions[finalPendingStateNum].stateRoot == newStateRoot ) { revert StoredRootMustBeDifferentThanNewRoot(); } } /** * @notice Function to activate emergency state, which also enables the emergency mode on both PolygonZkEVM and PolygonZkEVMBridge contracts * If not called by the owner must be provided a batcnNum that does not have been aggregated in a _HALT_AGGREGATION_TIMEOUT period * @param sequencedBatchNum Sequenced batch number that has not been aggreagated in _HALT_AGGREGATION_TIMEOUT */ function activateEmergencyState(uint64 sequencedBatchNum) external { if (msg.sender != owner()) { // Only check conditions if is not called by the owner uint64 currentLastVerifiedBatch = getLastVerifiedBatch(); // Check that the batch has not been verified if (sequencedBatchNum <= currentLastVerifiedBatch) { revert BatchAlreadyVerified(); } // Check that the batch has been sequenced and this was the end of a sequence if ( sequencedBatchNum > lastBatchSequenced || sequencedBatches[sequencedBatchNum].sequencedTimestamp == 0 ) { revert BatchNotSequencedOrNotSequenceEnd(); } // Check that has been passed _HALT_AGGREGATION_TIMEOUT since it was sequenced if ( sequencedBatches[sequencedBatchNum].sequencedTimestamp + _HALT_AGGREGATION_TIMEOUT > block.timestamp ) { revert HaltTimeoutNotExpired(); } } _activateEmergencyState(); } /** * @notice Function to deactivate emergency state on both PolygonZkEVM and PolygonZkEVMBridge contracts */ function deactivateEmergencyState() external onlyAdmin { // Deactivate emergency state on PolygonZkEVMBridge bridgeAddress.deactivateEmergencyState(); // Deactivate emergency state on this contract super._deactivateEmergencyState(); } /** * @notice Internal function to activate emergency state on both PolygonZkEVM and PolygonZkEVMBridge contracts */ function _activateEmergencyState() internal override { // Activate emergency state on PolygonZkEVM Bridge bridgeAddress.activateEmergencyState(); // Activate emergency state on this contract super._activateEmergencyState(); } //////////////////////// // public/view functions //////////////////////// /** * @notice Get forced batch fee */ function getForcedBatchFee() public view returns (uint256) { return batchFee * 100; } /** * @notice Get the last verified batch */ function getLastVerifiedBatch() public view returns (uint64) { if (lastPendingState > 0) { return pendingStateTransitions[lastPendingState].lastVerifiedBatch; } else { return lastVerifiedBatch; } } /** * @notice Returns a boolean that indicates if the pendingStateNum is or not consolidable * Note that his function does not check if the pending state currently exists, or if it's consolidated already */ function isPendingStateConsolidable( uint64 pendingStateNum ) public view returns (bool) { return (pendingStateTransitions[pendingStateNum].timestamp + pendingStateTimeout <= block.timestamp); } /** * @notice Function to calculate the reward to verify a single batch */ function calculateRewardPerBatch() public view returns (uint256) { uint256 currentBalance = matic.balanceOf(address(this)); // Total Sequenced Batches = forcedBatches to be sequenced (total forced Batches - sequenced Batches) + sequencedBatches // Total Batches to be verified = Total Sequenced Batches - verified Batches uint256 totalBatchesToVerify = ((lastForceBatch - lastForceBatchSequenced) + lastBatchSequenced) - getLastVerifiedBatch(); if (totalBatchesToVerify == 0) return 0; return currentBalance / totalBatchesToVerify; } /** * @notice Function to calculate the input snark bytes * @param initNumBatch Batch which the aggregator starts the verification * @param finalNewBatch Last batch aggregator intends to verify * @param newLocalExitRoot New local exit root once the batch is processed * @param oldStateRoot State root before batch is processed * @param newStateRoot New State root once the batch is processed */ function getInputSnarkBytes( uint64 initNumBatch, uint64 finalNewBatch, bytes32 newLocalExitRoot, bytes32 oldStateRoot, bytes32 newStateRoot ) public view returns (bytes memory) { // sanity checks bytes32 oldAccInputHash = sequencedBatches[initNumBatch].accInputHash; bytes32 newAccInputHash = sequencedBatches[finalNewBatch].accInputHash; if (initNumBatch != 0 && oldAccInputHash == bytes32(0)) { revert OldAccInputHashDoesNotExist(); } if (newAccInputHash == bytes32(0)) { revert NewAccInputHashDoesNotExist(); } // Check that new state root is inside goldilocks field if (!checkStateRootInsidePrime(uint256(newStateRoot))) { revert NewStateRootNotInsidePrime(); } return abi.encodePacked( msg.sender, oldStateRoot, oldAccInputHash, initNumBatch, chainID, forkID, newStateRoot, newAccInputHash, newLocalExitRoot, finalNewBatch ); } function checkStateRootInsidePrime( uint256 newStateRoot ) public pure returns (bool) { if ( ((newStateRoot & _MAX_UINT_64) < _GOLDILOCKS_PRIME_FIELD) && (((newStateRoot >> 64) & _MAX_UINT_64) < _GOLDILOCKS_PRIME_FIELD) && (((newStateRoot >> 128) & _MAX_UINT_64) < _GOLDILOCKS_PRIME_FIELD) && ((newStateRoot >> 192) < _GOLDILOCKS_PRIME_FIELD) ) { return true; } else { return false; } } }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.20; interface IBasePolygonZkEVMGlobalExitRoot { /** * @dev Thrown when the caller is not the allowed contracts */ error OnlyAllowedContracts(); function updateExitRoot(bytes32 newRollupExitRoot) external; function globalExitRootMap( bytes32 globalExitRootNum ) external returns (uint256); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.20; interface IPolygonZkEVMBridge { /** * @dev Thrown when sender is not the PolygonZkEVM address */ error OnlyPolygonZkEVM(); /** * @dev Thrown when the destination network is invalid */ error DestinationNetworkInvalid(); /** * @dev Thrown when the amount does not match msg.value */ error AmountDoesNotMatchMsgValue(); /** * @dev Thrown when user is bridging tokens and is also sending a value */ error MsgValueNotZero(); /** * @dev Thrown when the Ether transfer on claimAsset fails */ error EtherTransferFailed(); /** * @dev Thrown when the message transaction on claimMessage fails */ error MessageFailed(); /** * @dev Thrown when the global exit root does not exist */ error GlobalExitRootInvalid(); /** * @dev Thrown when the smt proof does not match */ error InvalidSmtProof(); /** * @dev Thrown when an index is already claimed */ error AlreadyClaimed(); /** * @dev Thrown when the owner of permit does not match the sender */ error NotValidOwner(); /** * @dev Thrown when the spender of the permit does not match this contract address */ error NotValidSpender(); /** * @dev Thrown when the amount of the permit does not match */ error NotValidAmount(); /** * @dev Thrown when the permit data contains an invalid signature */ error NotValidSignature(); function bridgeAsset( uint32 destinationNetwork, address destinationAddress, uint256 amount, address token, bool forceUpdateGlobalExitRoot, bytes calldata permitData ) external payable; function bridgeMessage( uint32 destinationNetwork, address destinationAddress, bool forceUpdateGlobalExitRoot, bytes calldata metadata ) external payable; function claimAsset( bytes32[32] calldata smtProof, uint32 index, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originTokenAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes calldata metadata ) external; function claimMessage( bytes32[32] calldata smtProof, uint32 index, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes calldata metadata ) external; function updateGlobalExitRoot() external; function activateEmergencyState() external; function deactivateEmergencyState() external; }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.20; interface IPolygonZkEVMErrors { /** * @dev Thrown when the pending state timeout exceeds the _HALT_AGGREGATION_TIMEOUT */ error PendingStateTimeoutExceedHaltAggregationTimeout(); /** * @dev Thrown when the trusted aggregator timeout exceeds the _HALT_AGGREGATION_TIMEOUT */ error TrustedAggregatorTimeoutExceedHaltAggregationTimeout(); /** * @dev Thrown when the caller is not the admin */ error OnlyAdmin(); /** * @dev Thrown when the caller is not the trusted sequencer */ error OnlyTrustedSequencer(); /** * @dev Thrown when the caller is not the trusted aggregator */ error OnlyTrustedAggregator(); /** * @dev Thrown when attempting to sequence 0 batches */ error SequenceZeroBatches(); /** * @dev Thrown when attempting to sequence or verify more batches than _MAX_VERIFY_BATCHES */ error ExceedMaxVerifyBatches(); /** * @dev Thrown when the forced data does not match */ error ForcedDataDoesNotMatch(); /** * @dev Thrown when the sequenced timestamp is below the forced minimum timestamp */ error SequencedTimestampBelowForcedTimestamp(); /** * @dev Thrown when a global exit root is not zero and does not exist */ error GlobalExitRootNotExist(); /** * @dev Thrown when transactions array length is above _MAX_TRANSACTIONS_BYTE_LENGTH. */ error TransactionsLengthAboveMax(); /** * @dev Thrown when a sequenced timestamp is not inside a correct range. */ error SequencedTimestampInvalid(); /** * @dev Thrown when there are more sequenced force batches than were actually submitted, should be unreachable */ error ForceBatchesOverflow(); /** * @dev Thrown when there are more sequenced force batches than were actually submitted */ error TrustedAggregatorTimeoutNotExpired(); /** * @dev Thrown when attempting to access a pending state that does not exist */ error PendingStateDoesNotExist(); /** * @dev Thrown when the init num batch does not match with the one in the pending state */ error InitNumBatchDoesNotMatchPendingState(); /** * @dev Thrown when the old state root of a certain batch does not exist */ error OldStateRootDoesNotExist(); /** * @dev Thrown when the init verification batch is above the last verification batch */ error InitNumBatchAboveLastVerifiedBatch(); /** * @dev Thrown when the final verification batch is below or equal the last verification batch */ error FinalNumBatchBelowLastVerifiedBatch(); /** * @dev Thrown when the zkproof is not valid */ error InvalidProof(); /** * @dev Thrown when attempting to consolidate a pending state not yet consolidable */ error PendingStateNotConsolidable(); /** * @dev Thrown when attempting to consolidate a pending state that is already consolidated or does not exist */ error PendingStateInvalid(); /** * @dev Thrown when the matic amount is below the necessary matic fee */ error NotEnoughMaticAmount(); /** * @dev Thrown when attempting to sequence a force batch using sequenceForceBatches and the * force timeout did not expire */ error ForceBatchTimeoutNotExpired(); /** * @dev Thrown when attempting to set a new trusted aggregator timeout equal or bigger than current one */ error NewTrustedAggregatorTimeoutMustBeLower(); /** * @dev Thrown when attempting to set a new pending state timeout equal or bigger than current one */ error NewPendingStateTimeoutMustBeLower(); /** * @dev Thrown when attempting to set a new multiplier batch fee in a invalid range of values */ error InvalidRangeMultiplierBatchFee(); /** * @dev Thrown when attempting to set a batch time target in an invalid range of values */ error InvalidRangeBatchTimeTarget(); /** * @dev Thrown when attempting to set a force batch timeout in an invalid range of values */ error InvalidRangeForceBatchTimeout(); /** * @dev Thrown when the caller is not the pending admin */ error OnlyPendingAdmin(); /** * @dev Thrown when the final pending state num is not in a valid range */ error FinalPendingStateNumInvalid(); /** * @dev Thrown when the final num batch does not match with the one in the pending state */ error FinalNumBatchDoesNotMatchPendingState(); /** * @dev Thrown when the stored root matches the new root proving a different state */ error StoredRootMustBeDifferentThanNewRoot(); /** * @dev Thrown when the batch is already verified when attempting to activate the emergency state */ error BatchAlreadyVerified(); /** * @dev Thrown when the batch is not sequenced or not at the end of a sequence when attempting to activate the emergency state */ error BatchNotSequencedOrNotSequenceEnd(); /** * @dev Thrown when the halt timeout is not expired when attempting to activate the emergency state */ error HaltTimeoutNotExpired(); /** * @dev Thrown when the old accumulate input hash does not exist */ error OldAccInputHashDoesNotExist(); /** * @dev Thrown when the new accumulate input hash does not exist */ error NewAccInputHashDoesNotExist(); /** * @dev Thrown when the new state root is not inside prime */ error NewStateRootNotInsidePrime(); /** * @dev Thrown when force batch is not allowed */ error ForceBatchNotAllowed(); /** * @dev Thrown when try to activate force batches when they are already active */ error ForceBatchesAlreadyActive(); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.20; import "./IBasePolygonZkEVMGlobalExitRoot.sol"; interface IPolygonZkEVMGlobalExitRoot is IBasePolygonZkEVMGlobalExitRoot { function getLastGlobalExitRoot() external view returns (bytes32); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.20; /** * @dev Define interface verifier */ interface IVerifierRollup { function verifyProof( bytes32[24] calldata proof, uint256[1] calldata pubSignals ) external view returns (bool); }
// SPDX-License-Identifier: AGPL-3.0 pragma solidity ^0.8.20; /** * @dev Contract helper responsible to manage the emergency state */ contract EmergencyManager { /** * @dev Thrown when emergency state is active, and the function requires otherwise */ error OnlyNotEmergencyState(); /** * @dev Thrown when emergency state is not active, and the function requires otherwise */ error OnlyEmergencyState(); /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. */ uint256[10] private _gap; // Indicates whether the emergency state is active or not bool public isEmergencyState; /** * @dev Emitted when emergency state is activated */ event EmergencyStateActivated(); /** * @dev Emitted when emergency state is deactivated */ event EmergencyStateDeactivated(); /** * @notice Only allows a function to be callable if emergency state is unactive */ modifier ifNotEmergencyState() { if (isEmergencyState) { revert OnlyNotEmergencyState(); } _; } /** * @notice Only allows a function to be callable if emergency state is active */ modifier ifEmergencyState() { if (!isEmergencyState) { revert OnlyEmergencyState(); } _; } /** * @notice Activate emergency state */ function _activateEmergencyState() internal virtual ifNotEmergencyState { isEmergencyState = true; emit EmergencyStateActivated(); } /** * @notice Deactivate emergency state */ function _deactivateEmergencyState() internal virtual ifEmergencyState { isEmergencyState = false; emit EmergencyStateDeactivated(); } }
{ "evmVersion": "shanghai", "optimizer": { "enabled": true, "runs": 999999 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"uint256","name":"minDelay","type":"uint256"},{"internalType":"address[]","name":"proposers","type":"address[]"},{"internalType":"address[]","name":"executors","type":"address[]"},{"internalType":"address","name":"admin","type":"address"},{"internalType":"contract PolygonZkEVM","name":"_polygonZkEVM","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"CallExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"bytes32","name":"predecessor","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"delay","type":"uint256"}],"name":"CallScheduled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"Cancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldDuration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newDuration","type":"uint256"}],"name":"MinDelayChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"CANCELLER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXECUTOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROPOSER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TIMELOCK_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"bytes32","name":"predecessor","type":"bytes32"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes[]","name":"payloads","type":"bytes[]"},{"internalType":"bytes32","name":"predecessor","type":"bytes32"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"executeBatch","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getMinDelay","outputs":[{"internalType":"uint256","name":"duration","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"getTimestamp","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes32","name":"predecessor","type":"bytes32"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"hashOperation","outputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes[]","name":"payloads","type":"bytes[]"},{"internalType":"bytes32","name":"predecessor","type":"bytes32"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"hashOperationBatch","outputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"isOperation","outputs":[{"internalType":"bool","name":"registered","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"isOperationDone","outputs":[{"internalType":"bool","name":"done","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"isOperationPending","outputs":[{"internalType":"bool","name":"pending","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"isOperationReady","outputs":[{"internalType":"bool","name":"ready","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"polygonZkEVM","outputs":[{"internalType":"contract PolygonZkEVM","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes32","name":"predecessor","type":"bytes32"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256","name":"delay","type":"uint256"}],"name":"schedule","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes[]","name":"payloads","type":"bytes[]"},{"internalType":"bytes32","name":"predecessor","type":"bytes32"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256","name":"delay","type":"uint256"}],"name":"scheduleBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"newDelay","type":"uint256"}],"name":"updateDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6080604052600436106101bd575f3560e01c806364d62353116100f2578063b1c5f42711610092578063d547741f11610062578063d547741f1461063a578063e38335e514610659578063f23a6e611461066c578063f27a0c92146106b0575f80fd5b8063b1c5f4271461058d578063bc197c81146105ac578063c4d252f5146105f0578063d45c44351461060f575f80fd5b80638f61f4f5116100cd5780638f61f4f5146104c557806391d14854146104f8578063a217fddf14610547578063b08e51c01461055a575f80fd5b806364d62353146104685780638065657f146104875780638f2a0bb0146104a6575f80fd5b8063248a9ca31161015d57806331d507501161013857806331d50750146103b357806336568abe146103d25780633a6aae72146103f1578063584b153e14610449575f80fd5b8063248a9ca3146103375780632ab0f529146103655780632f2ff15d14610394575f80fd5b80630d3cf6fc116101985780630d3cf6fc1461025e578063134008d31461029157806313bc9f20146102a4578063150b7a02146102c3575f80fd5b806301d5062a146101c857806301ffc9a7146101e957806307bd02651461021d575f80fd5b366101c457005b5f80fd5b3480156101d3575f80fd5b506101e76101e2366004611bf6565b6106c4565b005b3480156101f4575f80fd5b50610208610203366004611c65565b610757565b60405190151581526020015b60405180910390f35b348015610228575f80fd5b506102507fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6381565b604051908152602001610214565b348015610269575f80fd5b506102507f5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca581565b6101e761029f366004611ca4565b6107b2565b3480156102af575f80fd5b506102086102be366004611d0b565b6108a7565b3480156102ce575f80fd5b506103066102dd366004611e28565b7f150b7a0200000000000000000000000000000000000000000000000000000000949350505050565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610214565b348015610342575f80fd5b50610250610351366004611d0b565b5f9081526020819052604090206001015490565b348015610370575f80fd5b5061020861037f366004611d0b565b5f908152600160208190526040909120541490565b34801561039f575f80fd5b506101e76103ae366004611e8c565b6108cc565b3480156103be575f80fd5b506102086103cd366004611d0b565b6108f5565b3480156103dd575f80fd5b506101e76103ec366004611e8c565b61090d565b3480156103fc575f80fd5b506104247f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610214565b348015610454575f80fd5b50610208610463366004611d0b565b6109c5565b348015610473575f80fd5b506101e7610482366004611d0b565b6109da565b348015610492575f80fd5b506102506104a1366004611ca4565b610aaa565b3480156104b1575f80fd5b506101e76104c0366004611ef7565b610ae8565b3480156104d0575f80fd5b506102507fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc181565b348015610503575f80fd5b50610208610512366004611e8c565b5f9182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b348015610552575f80fd5b506102505f81565b348015610565575f80fd5b506102507ffd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f78381565b348015610598575f80fd5b506102506105a7366004611fa0565b610d18565b3480156105b7575f80fd5b506103066105c63660046120be565b7fbc197c810000000000000000000000000000000000000000000000000000000095945050505050565b3480156105fb575f80fd5b506101e761060a366004611d0b565b610d5c565b34801561061a575f80fd5b50610250610629366004611d0b565b5f9081526001602052604090205490565b348015610645575f80fd5b506101e7610654366004611e8c565b610e56565b6101e7610667366004611fa0565b610e7a565b348015610677575f80fd5b50610306610686366004612161565b7ff23a6e610000000000000000000000000000000000000000000000000000000095945050505050565b3480156106bb575f80fd5b50610250611121565b7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc16106ee81611200565b5f6106fd898989898989610aaa565b9050610709818461120d565b5f817f4cf4410cc57040e44862ef0f45f3dd5a5e02db8eb8add648d4b0e236f1d07dca8b8b8b8b8b8a60405161074496959493929190612208565b60405180910390a3505050505050505050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f4e2312e00000000000000000000000000000000000000000000000000000000014806107ac57506107ac82611359565b92915050565b5f80527fdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d70696020527f5ba6852781629bcdcd4bdaa6de76d786f1c64b16acdac474e55bebc0ea157951547fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e639060ff1661082e5761082e81336113ef565b5f61083d888888888888610aaa565b905061084981856114a6565b610855888888886115e2565b5f817fc2617efa69bab66782fa219543714338489c4e9e178271560a91b82c3f612b588a8a8a8a60405161088c9493929190612252565b60405180910390a361089d816116e2565b5050505050505050565b5f818152600160205260408120546001811180156108c55750428111155b9392505050565b5f828152602081905260409020600101546108e681611200565b6108f0838361178a565b505050565b5f8181526001602052604081205481905b1192915050565b73ffffffffffffffffffffffffffffffffffffffff811633146109b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b6109c18282611878565b5050565b5f818152600160208190526040822054610906565b333014610a69576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f54696d656c6f636b436f6e74726f6c6c65723a2063616c6c6572206d7573742060448201527f62652074696d656c6f636b00000000000000000000000000000000000000000060648201526084016109ae565b60025460408051918252602082018390527f11c24f4ead16507c69ac467fbd5e4eed5fb5c699626d2cc6d66421df253886d5910160405180910390a1600255565b5f868686868686604051602001610ac696959493929190612208565b6040516020818303038152906040528051906020012090509695505050505050565b7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1610b1281611200565b888714610ba1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b888514610c30576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b5f610c418b8b8b8b8b8b8b8b610d18565b9050610c4d818461120d565b5f5b8a811015610d0a5780827f4cf4410cc57040e44862ef0f45f3dd5a5e02db8eb8add648d4b0e236f1d07dca8e8e85818110610c8c57610c8c612291565b9050602002016020810190610ca191906122be565b8d8d86818110610cb357610cb3612291565b905060200201358c8c87818110610ccc57610ccc612291565b9050602002810190610cde91906122d7565b8c8b604051610cf296959493929190612208565b60405180910390a3610d0381612365565b9050610c4f565b505050505050505050505050565b5f8888888888888888604051602001610d38989796959493929190612447565b60405160208183030381529060405280519060200120905098975050505050505050565b7ffd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f783610d8681611200565b610d8f826109c5565b610e1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20636160448201527f6e6e6f742062652063616e63656c6c656400000000000000000000000000000060648201526084016109ae565b5f828152600160205260408082208290555183917fbaa1eb22f2a492ba1a5fea61b8df4d27c6c8b5f3971e63bb58fa14ff72eedb7091a25050565b5f82815260208190526040902060010154610e7081611200565b6108f08383611878565b5f80527fdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d70696020527f5ba6852781629bcdcd4bdaa6de76d786f1c64b16acdac474e55bebc0ea157951547fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e639060ff16610ef657610ef681336113ef565b878614610f85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b878414611014576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b5f6110258a8a8a8a8a8a8a8a610d18565b905061103181856114a6565b5f5b8981101561110b575f8b8b8381811061104e5761104e612291565b905060200201602081019061106391906122be565b90505f8a8a8481811061107857611078612291565b905060200201359050365f8a8a8681811061109557611095612291565b90506020028101906110a791906122d7565b915091506110b7848484846115e2565b84867fc2617efa69bab66782fa219543714338489c4e9e178271560a91b82c3f612b58868686866040516110ee9493929190612252565b60405180910390a3505050508061110490612365565b9050611033565b50611115816116e2565b50505050505050505050565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16158015906111ef57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166315064c966040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111cb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ef919061250c565b156111f957505f90565b5060025490565b61120a81336113ef565b50565b611216826108f5565b156112a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20616c60448201527f7265616479207363686564756c6564000000000000000000000000000000000060648201526084016109ae565b6112ab611121565b81101561133a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f54696d656c6f636b436f6e74726f6c6c65723a20696e73756666696369656e7460448201527f2064656c6179000000000000000000000000000000000000000000000000000060648201526084016109ae565b611344814261252b565b5f928352600160205260409092209190915550565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806107ac57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146107ac565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff166109c15761142c8161192d565b61143783602061194c565b604051602001611448929190612560565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a00000000000000000000000000000000000000000000000000000000082526109ae916004016125e0565b6114af826108a7565b61153b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20697360448201527f206e6f742072656164790000000000000000000000000000000000000000000060648201526084016109ae565b80158061155657505f81815260016020819052604090912054145b6109c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f54696d656c6f636b436f6e74726f6c6c65723a206d697373696e67206465706560448201527f6e64656e6379000000000000000000000000000000000000000000000000000060648201526084016109ae565b5f8473ffffffffffffffffffffffffffffffffffffffff1684848460405161160b929190612630565b5f6040518083038185875af1925050503d805f8114611645576040519150601f19603f3d011682016040523d82523d5f602084013e61164a565b606091505b50509050806116db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603360248201527f54696d656c6f636b436f6e74726f6c6c65723a20756e6465726c79696e67207460448201527f72616e73616374696f6e2072657665727465640000000000000000000000000060648201526084016109ae565b5050505050565b6116eb816108a7565b611777576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20697360448201527f206e6f742072656164790000000000000000000000000000000000000000000060648201526084016109ae565b5f90815260016020819052604090912055565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff166109c1575f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561181a3390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16156109c1575f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60606107ac73ffffffffffffffffffffffffffffffffffffffff831660145b60605f61195a83600261263f565b61196590600261252b565b67ffffffffffffffff81111561197d5761197d611d22565b6040519080825280601f01601f1916602001820160405280156119a7576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000815f815181106119dd576119dd612291565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611a3f57611a3f612291565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f611a7984600261263f565b611a8490600161252b565b90505b6001811115611b20577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110611ac557611ac5612291565b1a60f81b828281518110611adb57611adb612291565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535060049490941c93611b1981612656565b9050611a87565b5083156108c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016109ae565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bac575f80fd5b919050565b5f8083601f840112611bc1575f80fd5b50813567ffffffffffffffff811115611bd8575f80fd5b602083019150836020828501011115611bef575f80fd5b9250929050565b5f805f805f805f60c0888a031215611c0c575f80fd5b611c1588611b89565b965060208801359550604088013567ffffffffffffffff811115611c37575f80fd5b611c438a828b01611bb1565b989b979a50986060810135976080820135975060a09091013595509350505050565b5f60208284031215611c75575f80fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146108c5575f80fd5b5f805f805f8060a08789031215611cb9575f80fd5b611cc287611b89565b955060208701359450604087013567ffffffffffffffff811115611ce4575f80fd5b611cf089828a01611bb1565b979a9699509760608101359660809091013595509350505050565b5f60208284031215611d1b575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611d9657611d96611d22565b604052919050565b5f82601f830112611dad575f80fd5b813567ffffffffffffffff811115611dc757611dc7611d22565b611df860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601611d4f565b818152846020838601011115611e0c575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f8060808587031215611e3b575f80fd5b611e4485611b89565b9350611e5260208601611b89565b925060408501359150606085013567ffffffffffffffff811115611e74575f80fd5b611e8087828801611d9e565b91505092959194509250565b5f8060408385031215611e9d575f80fd5b82359150611ead60208401611b89565b90509250929050565b5f8083601f840112611ec6575f80fd5b50813567ffffffffffffffff811115611edd575f80fd5b6020830191508360208260051b8501011115611bef575f80fd5b5f805f805f805f805f60c08a8c031215611f0f575f80fd5b893567ffffffffffffffff80821115611f26575f80fd5b611f328d838e01611eb6565b909b50995060208c0135915080821115611f4a575f80fd5b611f568d838e01611eb6565b909950975060408c0135915080821115611f6e575f80fd5b50611f7b8c828d01611eb6565b9a9d999c50979a969997986060880135976080810135975060a0013595509350505050565b5f805f805f805f8060a0898b031215611fb7575f80fd5b883567ffffffffffffffff80821115611fce575f80fd5b611fda8c838d01611eb6565b909a50985060208b0135915080821115611ff2575f80fd5b611ffe8c838d01611eb6565b909850965060408b0135915080821115612016575f80fd5b506120238b828c01611eb6565b999c989b509699959896976060870135966080013595509350505050565b5f82601f830112612050575f80fd5b8135602067ffffffffffffffff82111561206c5761206c611d22565b8160051b61207b828201611d4f565b9283528481018201928281019087851115612094575f80fd5b83870192505b848310156120b35782358252918301919083019061209a565b979650505050505050565b5f805f805f60a086880312156120d2575f80fd5b6120db86611b89565b94506120e960208701611b89565b9350604086013567ffffffffffffffff80821115612105575f80fd5b61211189838a01612041565b94506060880135915080821115612126575f80fd5b61213289838a01612041565b93506080880135915080821115612147575f80fd5b5061215488828901611d9e565b9150509295509295909350565b5f805f805f60a08688031215612175575f80fd5b61217e86611b89565b945061218c60208701611b89565b93506040860135925060608601359150608086013567ffffffffffffffff8111156121b5575f80fd5b61215488828901611d9e565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff8716815285602082015260a060408201525f61223d60a0830186886121c1565b60608301949094525060800152949350505050565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201525f6122876060830184866121c1565b9695505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f602082840312156122ce575f80fd5b6108c582611b89565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261230a575f80fd5b83018035915067ffffffffffffffff821115612324575f80fd5b602001915036819003821315611bef575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361239557612395612338565b5060010190565b8183525f6020808501808196508560051b81019150845f5b8781101561243a57828403895281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18836030181126123f2575f80fd5b8701858101903567ffffffffffffffff81111561240d575f80fd5b80360382131561241b575f80fd5b6124268682846121c1565b9a87019a95505050908401906001016123b4565b5091979650505050505050565b60a080825281018890525f8960c08301825b8b8110156124945773ffffffffffffffffffffffffffffffffffffffff61247f84611b89565b16825260209283019290910190600101612459565b5083810360208501528881527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8911156124cc575f80fd5b8860051b9150818a602083013701828103602090810160408501526124f4908201878961239c565b60608401959095525050608001529695505050505050565b5f6020828403121561251c575f80fd5b815180151581146108c5575f80fd5b808201808211156107ac576107ac612338565b5f5b83811015612558578181015183820152602001612540565b50505f910152565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f835161259781601785016020880161253e565b7f206973206d697373696e6720726f6c652000000000000000000000000000000060179184019182015283516125d481602884016020880161253e565b01602801949350505050565b602081525f82518060208401526125fe81604085016020870161253e565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b818382375f9101908152919050565b80820281158282048414176107ac576107ac612338565b5f8161266457612664612338565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea2646970667358221220e28ae7494480ab1c619fd775dc5ff665588c808a910d66178a982c2e7c76a1e664736f6c63430008140033
Deployed Bytecode
0x6080604052600436106101bd575f3560e01c806364d62353116100f2578063b1c5f42711610092578063d547741f11610062578063d547741f1461063a578063e38335e514610659578063f23a6e611461066c578063f27a0c92146106b0575f80fd5b8063b1c5f4271461058d578063bc197c81146105ac578063c4d252f5146105f0578063d45c44351461060f575f80fd5b80638f61f4f5116100cd5780638f61f4f5146104c557806391d14854146104f8578063a217fddf14610547578063b08e51c01461055a575f80fd5b806364d62353146104685780638065657f146104875780638f2a0bb0146104a6575f80fd5b8063248a9ca31161015d57806331d507501161013857806331d50750146103b357806336568abe146103d25780633a6aae72146103f1578063584b153e14610449575f80fd5b8063248a9ca3146103375780632ab0f529146103655780632f2ff15d14610394575f80fd5b80630d3cf6fc116101985780630d3cf6fc1461025e578063134008d31461029157806313bc9f20146102a4578063150b7a02146102c3575f80fd5b806301d5062a146101c857806301ffc9a7146101e957806307bd02651461021d575f80fd5b366101c457005b5f80fd5b3480156101d3575f80fd5b506101e76101e2366004611bf6565b6106c4565b005b3480156101f4575f80fd5b50610208610203366004611c65565b610757565b60405190151581526020015b60405180910390f35b348015610228575f80fd5b506102507fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e6381565b604051908152602001610214565b348015610269575f80fd5b506102507f5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca581565b6101e761029f366004611ca4565b6107b2565b3480156102af575f80fd5b506102086102be366004611d0b565b6108a7565b3480156102ce575f80fd5b506103066102dd366004611e28565b7f150b7a0200000000000000000000000000000000000000000000000000000000949350505050565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610214565b348015610342575f80fd5b50610250610351366004611d0b565b5f9081526020819052604090206001015490565b348015610370575f80fd5b5061020861037f366004611d0b565b5f908152600160208190526040909120541490565b34801561039f575f80fd5b506101e76103ae366004611e8c565b6108cc565b3480156103be575f80fd5b506102086103cd366004611d0b565b6108f5565b3480156103dd575f80fd5b506101e76103ec366004611e8c565b61090d565b3480156103fc575f80fd5b506104247f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610214565b348015610454575f80fd5b50610208610463366004611d0b565b6109c5565b348015610473575f80fd5b506101e7610482366004611d0b565b6109da565b348015610492575f80fd5b506102506104a1366004611ca4565b610aaa565b3480156104b1575f80fd5b506101e76104c0366004611ef7565b610ae8565b3480156104d0575f80fd5b506102507fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc181565b348015610503575f80fd5b50610208610512366004611e8c565b5f9182526020828152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b348015610552575f80fd5b506102505f81565b348015610565575f80fd5b506102507ffd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f78381565b348015610598575f80fd5b506102506105a7366004611fa0565b610d18565b3480156105b7575f80fd5b506103066105c63660046120be565b7fbc197c810000000000000000000000000000000000000000000000000000000095945050505050565b3480156105fb575f80fd5b506101e761060a366004611d0b565b610d5c565b34801561061a575f80fd5b50610250610629366004611d0b565b5f9081526001602052604090205490565b348015610645575f80fd5b506101e7610654366004611e8c565b610e56565b6101e7610667366004611fa0565b610e7a565b348015610677575f80fd5b50610306610686366004612161565b7ff23a6e610000000000000000000000000000000000000000000000000000000095945050505050565b3480156106bb575f80fd5b50610250611121565b7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc16106ee81611200565b5f6106fd898989898989610aaa565b9050610709818461120d565b5f817f4cf4410cc57040e44862ef0f45f3dd5a5e02db8eb8add648d4b0e236f1d07dca8b8b8b8b8b8a60405161074496959493929190612208565b60405180910390a3505050505050505050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f4e2312e00000000000000000000000000000000000000000000000000000000014806107ac57506107ac82611359565b92915050565b5f80527fdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d70696020527f5ba6852781629bcdcd4bdaa6de76d786f1c64b16acdac474e55bebc0ea157951547fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e639060ff1661082e5761082e81336113ef565b5f61083d888888888888610aaa565b905061084981856114a6565b610855888888886115e2565b5f817fc2617efa69bab66782fa219543714338489c4e9e178271560a91b82c3f612b588a8a8a8a60405161088c9493929190612252565b60405180910390a361089d816116e2565b5050505050505050565b5f818152600160205260408120546001811180156108c55750428111155b9392505050565b5f828152602081905260409020600101546108e681611200565b6108f0838361178a565b505050565b5f8181526001602052604081205481905b1192915050565b73ffffffffffffffffffffffffffffffffffffffff811633146109b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c66000000000000000000000000000000000060648201526084015b60405180910390fd5b6109c18282611878565b5050565b5f818152600160208190526040822054610906565b333014610a69576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f54696d656c6f636b436f6e74726f6c6c65723a2063616c6c6572206d7573742060448201527f62652074696d656c6f636b00000000000000000000000000000000000000000060648201526084016109ae565b60025460408051918252602082018390527f11c24f4ead16507c69ac467fbd5e4eed5fb5c699626d2cc6d66421df253886d5910160405180910390a1600255565b5f868686868686604051602001610ac696959493929190612208565b6040516020818303038152906040528051906020012090509695505050505050565b7fb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1610b1281611200565b888714610ba1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b888514610c30576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b5f610c418b8b8b8b8b8b8b8b610d18565b9050610c4d818461120d565b5f5b8a811015610d0a5780827f4cf4410cc57040e44862ef0f45f3dd5a5e02db8eb8add648d4b0e236f1d07dca8e8e85818110610c8c57610c8c612291565b9050602002016020810190610ca191906122be565b8d8d86818110610cb357610cb3612291565b905060200201358c8c87818110610ccc57610ccc612291565b9050602002810190610cde91906122d7565b8c8b604051610cf296959493929190612208565b60405180910390a3610d0381612365565b9050610c4f565b505050505050505050505050565b5f8888888888888888604051602001610d38989796959493929190612447565b60405160208183030381529060405280519060200120905098975050505050505050565b7ffd643c72710c63c0180259aba6b2d05451e3591a24e58b62239378085726f783610d8681611200565b610d8f826109c5565b610e1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603160248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20636160448201527f6e6e6f742062652063616e63656c6c656400000000000000000000000000000060648201526084016109ae565b5f828152600160205260408082208290555183917fbaa1eb22f2a492ba1a5fea61b8df4d27c6c8b5f3971e63bb58fa14ff72eedb7091a25050565b5f82815260208190526040902060010154610e7081611200565b6108f08383611878565b5f80527fdae2aa361dfd1ca020a396615627d436107c35eff9fe7738a3512819782d70696020527f5ba6852781629bcdcd4bdaa6de76d786f1c64b16acdac474e55bebc0ea157951547fd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e639060ff16610ef657610ef681336113ef565b878614610f85576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b878414611014576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f54696d656c6f636b436f6e74726f6c6c65723a206c656e677468206d69736d6160448201527f746368000000000000000000000000000000000000000000000000000000000060648201526084016109ae565b5f6110258a8a8a8a8a8a8a8a610d18565b905061103181856114a6565b5f5b8981101561110b575f8b8b8381811061104e5761104e612291565b905060200201602081019061106391906122be565b90505f8a8a8481811061107857611078612291565b905060200201359050365f8a8a8681811061109557611095612291565b90506020028101906110a791906122d7565b915091506110b7848484846115e2565b84867fc2617efa69bab66782fa219543714338489c4e9e178271560a91b82c3f612b58868686866040516110ee9493929190612252565b60405180910390a3505050508061110490612365565b9050611033565b50611115816116e2565b50505050505050505050565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16158015906111ef57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166315064c966040518163ffffffff1660e01b8152600401602060405180830381865afa1580156111cb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ef919061250c565b156111f957505f90565b5060025490565b61120a81336113ef565b50565b611216826108f5565b156112a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20616c60448201527f7265616479207363686564756c6564000000000000000000000000000000000060648201526084016109ae565b6112ab611121565b81101561133a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f54696d656c6f636b436f6e74726f6c6c65723a20696e73756666696369656e7460448201527f2064656c6179000000000000000000000000000000000000000000000000000060648201526084016109ae565b611344814261252b565b5f928352600160205260409092209190915550565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806107ac57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146107ac565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff166109c15761142c8161192d565b61143783602061194c565b604051602001611448929190612560565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a00000000000000000000000000000000000000000000000000000000082526109ae916004016125e0565b6114af826108a7565b61153b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20697360448201527f206e6f742072656164790000000000000000000000000000000000000000000060648201526084016109ae565b80158061155657505f81815260016020819052604090912054145b6109c1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f54696d656c6f636b436f6e74726f6c6c65723a206d697373696e67206465706560448201527f6e64656e6379000000000000000000000000000000000000000000000000000060648201526084016109ae565b5f8473ffffffffffffffffffffffffffffffffffffffff1684848460405161160b929190612630565b5f6040518083038185875af1925050503d805f8114611645576040519150601f19603f3d011682016040523d82523d5f602084013e61164a565b606091505b50509050806116db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603360248201527f54696d656c6f636b436f6e74726f6c6c65723a20756e6465726c79696e67207460448201527f72616e73616374696f6e2072657665727465640000000000000000000000000060648201526084016109ae565b5050505050565b6116eb816108a7565b611777576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f54696d656c6f636b436f6e74726f6c6c65723a206f7065726174696f6e20697360448201527f206e6f742072656164790000000000000000000000000000000000000000000060648201526084016109ae565b5f90815260016020819052604090912055565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff166109c1575f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905561181a3390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b5f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16156109c1575f8281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60606107ac73ffffffffffffffffffffffffffffffffffffffff831660145b60605f61195a83600261263f565b61196590600261252b565b67ffffffffffffffff81111561197d5761197d611d22565b6040519080825280601f01601f1916602001820160405280156119a7576020820181803683370190505b5090507f3000000000000000000000000000000000000000000000000000000000000000815f815181106119dd576119dd612291565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053507f780000000000000000000000000000000000000000000000000000000000000081600181518110611a3f57611a3f612291565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053505f611a7984600261263f565b611a8490600161252b565b90505b6001811115611b20577f303132333435363738396162636465660000000000000000000000000000000085600f1660108110611ac557611ac5612291565b1a60f81b828281518110611adb57611adb612291565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535060049490941c93611b1981612656565b9050611a87565b5083156108c5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016109ae565b803573ffffffffffffffffffffffffffffffffffffffff81168114611bac575f80fd5b919050565b5f8083601f840112611bc1575f80fd5b50813567ffffffffffffffff811115611bd8575f80fd5b602083019150836020828501011115611bef575f80fd5b9250929050565b5f805f805f805f60c0888a031215611c0c575f80fd5b611c1588611b89565b965060208801359550604088013567ffffffffffffffff811115611c37575f80fd5b611c438a828b01611bb1565b989b979a50986060810135976080820135975060a09091013595509350505050565b5f60208284031215611c75575f80fd5b81357fffffffff00000000000000000000000000000000000000000000000000000000811681146108c5575f80fd5b5f805f805f8060a08789031215611cb9575f80fd5b611cc287611b89565b955060208701359450604087013567ffffffffffffffff811115611ce4575f80fd5b611cf089828a01611bb1565b979a9699509760608101359660809091013595509350505050565b5f60208284031215611d1b575f80fd5b5035919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611d9657611d96611d22565b604052919050565b5f82601f830112611dad575f80fd5b813567ffffffffffffffff811115611dc757611dc7611d22565b611df860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601611d4f565b818152846020838601011115611e0c575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f8060808587031215611e3b575f80fd5b611e4485611b89565b9350611e5260208601611b89565b925060408501359150606085013567ffffffffffffffff811115611e74575f80fd5b611e8087828801611d9e565b91505092959194509250565b5f8060408385031215611e9d575f80fd5b82359150611ead60208401611b89565b90509250929050565b5f8083601f840112611ec6575f80fd5b50813567ffffffffffffffff811115611edd575f80fd5b6020830191508360208260051b8501011115611bef575f80fd5b5f805f805f805f805f60c08a8c031215611f0f575f80fd5b893567ffffffffffffffff80821115611f26575f80fd5b611f328d838e01611eb6565b909b50995060208c0135915080821115611f4a575f80fd5b611f568d838e01611eb6565b909950975060408c0135915080821115611f6e575f80fd5b50611f7b8c828d01611eb6565b9a9d999c50979a969997986060880135976080810135975060a0013595509350505050565b5f805f805f805f8060a0898b031215611fb7575f80fd5b883567ffffffffffffffff80821115611fce575f80fd5b611fda8c838d01611eb6565b909a50985060208b0135915080821115611ff2575f80fd5b611ffe8c838d01611eb6565b909850965060408b0135915080821115612016575f80fd5b506120238b828c01611eb6565b999c989b509699959896976060870135966080013595509350505050565b5f82601f830112612050575f80fd5b8135602067ffffffffffffffff82111561206c5761206c611d22565b8160051b61207b828201611d4f565b9283528481018201928281019087851115612094575f80fd5b83870192505b848310156120b35782358252918301919083019061209a565b979650505050505050565b5f805f805f60a086880312156120d2575f80fd5b6120db86611b89565b94506120e960208701611b89565b9350604086013567ffffffffffffffff80821115612105575f80fd5b61211189838a01612041565b94506060880135915080821115612126575f80fd5b61213289838a01612041565b93506080880135915080821115612147575f80fd5b5061215488828901611d9e565b9150509295509295909350565b5f805f805f60a08688031215612175575f80fd5b61217e86611b89565b945061218c60208701611b89565b93506040860135925060608601359150608086013567ffffffffffffffff8111156121b5575f80fd5b61215488828901611d9e565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff8716815285602082015260a060408201525f61223d60a0830186886121c1565b60608301949094525060800152949350505050565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152606060408201525f6122876060830184866121c1565b9695505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f602082840312156122ce575f80fd5b6108c582611b89565b5f8083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261230a575f80fd5b83018035915067ffffffffffffffff821115612324575f80fd5b602001915036819003821315611bef575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361239557612395612338565b5060010190565b8183525f6020808501808196508560051b81019150845f5b8781101561243a57828403895281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18836030181126123f2575f80fd5b8701858101903567ffffffffffffffff81111561240d575f80fd5b80360382131561241b575f80fd5b6124268682846121c1565b9a87019a95505050908401906001016123b4565b5091979650505050505050565b60a080825281018890525f8960c08301825b8b8110156124945773ffffffffffffffffffffffffffffffffffffffff61247f84611b89565b16825260209283019290910190600101612459565b5083810360208501528881527f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8911156124cc575f80fd5b8860051b9150818a602083013701828103602090810160408501526124f4908201878961239c565b60608401959095525050608001529695505050505050565b5f6020828403121561251c575f80fd5b815180151581146108c5575f80fd5b808201808211156107ac576107ac612338565b5f5b83811015612558578181015183820152602001612540565b50505f910152565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f835161259781601785016020880161253e565b7f206973206d697373696e6720726f6c652000000000000000000000000000000060179184019182015283516125d481602884016020880161253e565b01602801949350505050565b602081525f82518060208401526125fe81604085016020870161253e565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b818382375f9101908152919050565b80820281158282048414176107ac576107ac612338565b5f8161266457612664612338565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019056fea2646970667358221220e28ae7494480ab1c619fd775dc5ff665588c808a910d66178a982c2e7c76a1e664736f6c63430008140033
Deployed Bytecode Sourcemap
450:1377:19:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7618:402:9;;;;;;;;;;-1:-1:-1;7618:402:9;;;;;:::i;:::-;;:::i;:::-;;4770:228;;;;;;;;;;-1:-1:-1;4770:228:9;;;;;:::i;:::-;;:::i;:::-;;;1832:14:26;;1825:22;1807:41;;1795:2;1780:18;4770:228:9;;;;;;;;1272:66;;;;;;;;;;;;1312:26;1272:66;;;;;2005:25:26;;;1993:2;1978:18;1272:66:9;1859:177:26;1116:78:9;;;;;;;;;;;;1162:32;1116:78;;10216:459;;;;;;:::i;:::-;;:::i;5580:208::-;;;;;;;;;;-1:-1:-1;5580:208:9;;;;;:::i;:::-;;:::i;13714:200::-;;;;;;;;;;-1:-1:-1;13714:200:9;;;;;:::i;:::-;13877:30;13714:200;;;;;;;;;;4758:66:26;4746:79;;;4728:98;;4716:2;4701:18;13714:200:9;4584:248:26;4378:129:7;;;;;;;;;;-1:-1:-1;4378:129:7;;;;;:::i;:::-;4452:7;4478:12;;;;;;;;;;:22;;;;4378:129;5867:136:9;;;;;;;;;;-1:-1:-1;5867:136:9;;;;;:::i;:::-;5933:9;6249:15;;;1470:1;6249:15;;;;;;;;;5961:35;;5867:136;4803:145:7;;;;;;;;;;-1:-1:-1;4803:145:7;;;;;:::i;:::-;;:::i;5154:123:9:-;;;;;;;;;;-1:-1:-1;5154:123:9;;;;;:::i;:::-;;:::i;5912:214:7:-;;;;;;;;;;-1:-1:-1;5912:214:7;;;;;:::i;:::-;;:::i;589:42:19:-;;;;;;;;;;;;;;;;;;5293::26;5281:55;;;5263:74;;5251:2;5236:18;589:42:19;5096:247:26;5359:141:9;;;;;;;;;;-1:-1:-1;5359:141:9;;;;;:::i;:::-;;:::i;13404:236::-;;;;;;;;;;-1:-1:-1;13404:236:9;;;;;:::i;:::-;;:::i;6673:284::-;;;;;;;;;;-1:-1:-1;6673:284:9;;;;;:::i;:::-;;:::i;8274:713::-;;;;;;;;;;-1:-1:-1;8274:713:9;;;;;:::i;:::-;;:::i;1200:66::-;;;;;;;;;;;;1240:26;1200:66;;2895:145:7;;;;;;;;;;-1:-1:-1;2895:145:7;;;;;:::i;:::-;2981:4;3004:12;;;;;;;;;;;:29;;;;;;;;;;;;;;;;2895:145;2027:49;;;;;;;;;;-1:-1:-1;2027:49:7;2072:4;2027:49;;1344:68:9;;;;;;;;;;;;1385:27;1344:68;;7073:325;;;;;;;;;;-1:-1:-1;7073:325:9;;;;;:::i;:::-;;:::i;14290:247::-;;;;;;;;;;-1:-1:-1;14290:247:9;;;;;:::i;:::-;14494:36;14290:247;;;;;;;;9512:230;;;;;;;;;;-1:-1:-1;9512:230:9;;;;;:::i;:::-;;:::i;6150:121::-;;;;;;;;;;-1:-1:-1;6150:121:9;;;;;:::i;:::-;6213:17;6249:15;;;:11;:15;;;;;;;6150:121;5228:147:7;;;;;;;;;;-1:-1:-1;5228:147:7;;;;;:::i;:::-;;:::i;11183:883:9:-;;;;;;:::i;:::-;;:::i;13990:219::-;;;;;;;;;;-1:-1:-1;13990:219:9;;;;;:::i;:::-;14171:31;13990:219;;;;;;;;1572:253:19;;;;;;;;;;;;;:::i;7618:402:9:-;1240:26;2505:16:7;2516:4;2505:10;:16::i;:::-;7841:10:9::1;7854:53;7868:6;7876:5;7883:4;;7889:11;7902:4;7854:13;:53::i;:::-;7841:66;;7917:20;7927:2;7931:5;7917:9;:20::i;:::-;7970:1;7966:2;7952:61;7973:6;7981:5;7988:4;;7994:11;8007:5;7952:61;;;;;;;;;;;:::i;:::-;;;;;;;;7831:189;7618:402:::0;;;;;;;;:::o;4770:228::-;4879:4;4902:49;;;4917:34;4902:49;;:89;;;4955:36;4979:11;4955:23;:36::i;:::-;4895:96;4770:228;-1:-1:-1;;4770:228:9:o;10216:459::-;4495:1;3004:29:7;;:12;;:29;;;1312:26:9;;3004:29:7;;4468:87:9;;4514:30;4525:4;719:10:13;4514::9;:30::i;:::-;10436:10:::1;10449:56;10463:6;10471:5;10478:7;;10487:11;10500:4;10449:13;:56::i;:::-;10436:69;;10516:28;10528:2;10532:11;10516;:28::i;:::-;10554:32;10563:6;10571:5;10578:7;;10554:8;:32::i;:::-;10618:1;10614:2;10601:43;10621:6;10629:5;10636:7;;10601:43;;;;;;;;;:::i;:::-;;;;;;;;10654:14;10665:2;10654:10;:14::i;:::-;10426:249;10216:459:::0;;;;;;;:::o;5580:208::-;5647:10;6249:15;;;:11;:15;;;;;;1470:1;5722:9;:27;:59;;;;;5766:15;5753:9;:28;;5722:59;5715:66;5580:208;-1:-1:-1;;;5580:208:9:o;4803:145:7:-;4452:7;4478:12;;;;;;;;;;:22;;;2505:16;2516:4;2505:10;:16::i;:::-;4916:25:::1;4927:4;4933:7;4916:10;:25::i;:::-;4803:145:::0;;;:::o;5154:123:9:-;5216:15;6249;;;:11;:15;;;;;;5216;;5250:16;:20;;5154:123;-1:-1:-1;;5154:123:9:o;5912:214:7:-;6007:23;;;719:10:13;6007:23:7;5999:83;;;;;;;12473:2:26;5999:83:7;;;12455:21:26;12512:2;12492:18;;;12485:30;12551:34;12531:18;;;12524:62;12622:17;12602:18;;;12595:45;12657:19;;5999:83:7;;;;;;;;;6093:26;6105:4;6111:7;6093:11;:26::i;:::-;5912:214;;:::o;5359:141:9:-;5428:12;6249:15;;;1470:1;6249:15;;;;;;;;5459:16;6150:121;13404:236;13478:10;13500:4;13478:27;13470:83;;;;;;;12889:2:26;13470:83:9;;;12871:21:26;12928:2;12908:18;;;12901:30;12967:34;12947:18;;;12940:62;13038:13;13018:18;;;13011:41;13069:19;;13470:83:9;12687:407:26;13470:83:9;13583:9;;13568:35;;;13273:25:26;;;13329:2;13314:18;;13307:34;;;13568:35:9;;13246:18:26;13568:35:9;;;;;;;13613:9;:20;13404:236::o;6673:284::-;6858:12;6910:6;6918:5;6925:4;;6931:11;6944:4;6899:50;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;6889:61;;;;;;6882:68;;6673:284;;;;;;;;:::o;8274:713::-;1240:26;2505:16:7;2516:4;2505:10;:16::i;:::-;8540:31:9;;::::1;8532:79;;;::::0;::::1;::::0;;14139:2:26;8532:79:9::1;::::0;::::1;14121:21:26::0;14178:2;14158:18;;;14151:30;14217:34;14197:18;;;14190:62;14288:5;14268:18;;;14261:33;14311:19;;8532:79:9::1;13937:399:26::0;8532:79:9::1;8629:33:::0;;::::1;8621:81;;;::::0;::::1;::::0;;14139:2:26;8621:81:9::1;::::0;::::1;14121:21:26::0;14178:2;14158:18;;;14151:30;14217:34;14197:18;;;14190:62;14288:5;14268:18;;;14261:33;14311:19;;8621:81:9::1;13937:399:26::0;8621:81:9::1;8713:10;8726:64;8745:7;;8754:6;;8762:8;;8772:11;8785:4;8726:18;:64::i;:::-;8713:77;;8800:20;8810:2;8814:5;8800:9;:20::i;:::-;8835:9;8830:151;8850:18:::0;;::::1;8830:151;;;8912:1;8908:2;8894:76;8915:7;;8923:1;8915:10;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;8927:6;;8934:1;8927:9;;;;;;;:::i;:::-;;;;;;;8938:8;;8947:1;8938:11;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;8951;8964:5;8894:76;;;;;;;;;;;:::i;:::-;;;;;;;;8870:3;::::0;::::1;:::i;:::-;;;8830:151;;;;8522:465;8274:713:::0;;;;;;;;;;:::o;7073:325::-;7293:12;7345:7;;7354:6;;7362:8;;7372:11;7385:4;7334:56;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;7324:67;;;;;;7317:74;;7073:325;;;;;;;;;;:::o;9512:230::-;1385:27;2505:16:7;2516:4;2505:10;:16::i;:::-;9598:22:9::1;9617:2;9598:18;:22::i;:::-;9590:84;;;::::0;::::1;::::0;;18496:2:26;9590:84:9::1;::::0;::::1;18478:21:26::0;18535:2;18515:18;;;18508:30;18574:34;18554:18;;;18547:62;18645:19;18625:18;;;18618:47;18682:19;;9590:84:9::1;18294:413:26::0;9590:84:9::1;9691:15;::::0;;;:11:::1;:15;::::0;;;;;9684:22;;;9722:13;9703:2;;9722:13:::1;::::0;::::1;9512:230:::0;;:::o;5228:147:7:-;4452:7;4478:12;;;;;;;;;;:22;;;2505:16;2516:4;2505:10;:16::i;:::-;5342:26:::1;5354:4;5360:7;5342:11;:26::i;11183:883:9:-:0;4495:1;3004:29:7;;:12;;:29;;;1312:26:9;;3004:29:7;;4468:87:9;;4514:30;4525:4;719:10:13;4514::9;:30::i;:::-;11443:31;;::::1;11435:79;;;::::0;::::1;::::0;;14139:2:26;11435:79:9::1;::::0;::::1;14121:21:26::0;14178:2;14158:18;;;14151:30;14217:34;14197:18;;;14190:62;14288:5;14268:18;;;14261:33;14311:19;;11435:79:9::1;13937:399:26::0;11435:79:9::1;11532:33:::0;;::::1;11524:81;;;::::0;::::1;::::0;;14139:2:26;11524:81:9::1;::::0;::::1;14121:21:26::0;14178:2;14158:18;;;14151:30;14217:34;14197:18;;;14190:62;14288:5;14268:18;;;14261:33;14311:19;;11524:81:9::1;13937:399:26::0;11524:81:9::1;11616:10;11629:64;11648:7;;11657:6;;11665:8;;11675:11;11688:4;11629:18;:64::i;:::-;11616:77;;11704:28;11716:2;11720:11;11704;:28::i;:::-;11747:9;11742:294;11762:18:::0;;::::1;11742:294;;;11801:14;11818:7;;11826:1;11818:10;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;11801:27;;11842:13;11858:6;;11865:1;11858:9;;;;;;;:::i;:::-;;;;;;;11842:25;;11881:22;;11906:8;;11915:1;11906:11;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;11881:36;;;;11931:32;11940:6;11948:5;11955:7;;11931:8;:32::i;:::-;11999:1;11995:2;11982:43;12002:6;12010:5;12017:7;;11982:43;;;;;;;;;:::i;:::-;;;;;;;;11787:249;;;;11782:3;;;;:::i;:::-;;;11742:294;;;;12045:14;12056:2;12045:10;:14::i;:::-;11425:641;11183:883:::0;;;;;;;;;:::o;1572:253:19:-;1625:16;1665:12;1657:35;;;;;;:70;;;1696:12;:29;;;:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1653:166;;;-1:-1:-1;1750:1:19;;1572:253::o;1653:166::-;-1:-1:-1;6544:9:9;;;1572:253:19:o;3334:103:7:-;3400:30;3411:4;719:10:13;4514::9;:30::i;3400::7:-;3334:103;:::o;9089:281:9:-;9162:15;9174:2;9162:11;:15::i;:::-;9161:16;9153:76;;;;;;;19196:2:26;9153:76:9;;;19178:21:26;19235:2;19215:18;;;19208:30;19274:34;19254:18;;;19247:62;19345:17;19325:18;;;19318:45;19380:19;;9153:76:9;18994:411:26;9153:76:9;9256:13;:11;:13::i;:::-;9247:5;:22;;9239:73;;;;;;;19612:2:26;9239:73:9;;;19594:21:26;19651:2;19631:18;;;19624:30;19690:34;19670:18;;;19663:62;19761:8;19741:18;;;19734:36;19787:19;;9239:73:9;19410:402:26;9239:73:9;9340:23;9358:5;9340:15;:23;:::i;:::-;9322:15;;;;:11;:15;;;;;;:41;;;;-1:-1:-1;9089:281:9:o;2606:202:7:-;2691:4;2714:47;;;2729:32;2714:47;;:87;;-1:-1:-1;952:25:15;937:40;;;;2765:36:7;829:155:15;3718:479:7;2981:4;3004:12;;;;;;;;;;;:29;;;;;;;;;;;;;3801:390;;3989:28;4009:7;3989:19;:28::i;:::-;4088:38;4116:4;4123:2;4088:19;:38::i;:::-;3896:252;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;3844:336;;;;;;;;:::i;12477:277:9:-;12562:20;12579:2;12562:16;:20::i;:::-;12554:75;;;;;;;21681:2:26;12554:75:9;;;21663:21:26;21720:2;21700:18;;;21693:30;21759:34;21739:18;;;21732:62;21830:12;21810:18;;;21803:40;21860:19;;12554:75:9;21479:406:26;12554:75:9;12647:25;;;:57;;-1:-1:-1;5933:9:9;6249:15;;;1470:1;6249:15;;;;;;;;;5961:35;12676:28;12639:108;;;;;;;22092:2:26;12639:108:9;;;22074:21:26;22131:2;22111:18;;;22104:30;22170:34;22150:18;;;22143:62;22241:8;22221:18;;;22214:36;22267:19;;12639:108:9;21890:402:26;12129:265:9;12257:12;12275:6;:11;;12294:5;12301:4;;12275:31;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12256:50;;;12324:7;12316:71;;;;;;;22775:2:26;12316:71:9;;;22757:21:26;22814:2;22794:18;;;22787:30;22853:34;22833:18;;;22826:62;22924:21;22904:18;;;22897:49;22963:19;;12316:71:9;22573:415:26;12316:71:9;12246:148;12129:265;;;;:::o;12836:175::-;12894:20;12911:2;12894:16;:20::i;:::-;12886:75;;;;;;;21681:2:26;12886:75:9;;;21663:21:26;21720:2;21700:18;;;21693:30;21759:34;21739:18;;;21732:62;21830:12;21810:18;;;21803:40;21860:19;;12886:75:9;21479:406:26;12886:75:9;12971:15;;;;1470:1;12971:15;;;;;;;;:33;12836:175::o;7461:233:7:-;2981:4;3004:12;;;;;;;;;;;:29;;;;;;;;;;;;;7539:149;;7582:6;:12;;;;;;;;;;;:29;;;;;;;;;;:36;;;;7614:4;7582:36;;;7664:12;719:10:13;;640:96;7664:12:7;7637:40;;7655:7;7637:40;;7649:4;7637:40;;;;;;;;;;7461:233;;:::o;7865:234::-;2981:4;3004:12;;;;;;;;;;;:29;;;;;;;;;;;;;7944:149;;;8018:5;7986:12;;;;;;;;;;;:29;;;;;;;;;;;:37;;;;;;8042:40;719:10:13;;7986:12:7;;8042:40;;8018:5;8042:40;7865:234;;:::o;2102:149:14:-;2160:13;2192:52;2204:22;;;311:2;1513:437;1588:13;1613:19;1645:10;1649:6;1645:1;:10;:::i;:::-;:14;;1658:1;1645:14;:::i;:::-;1635:25;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1635:25:14;;1613:47;;1670:15;:6;1677:1;1670:9;;;;;;;;:::i;:::-;;;;:15;;;;;;;;;;;1695;:6;1702:1;1695:9;;;;;;;;:::i;:::-;;;;:15;;;;;;;;;;-1:-1:-1;1725:9:14;1737:10;1741:6;1737:1;:10;:::i;:::-;:14;;1750:1;1737:14;:::i;:::-;1725:26;;1720:128;1757:1;1753;:5;1720:128;;;1791:8;1800:5;1808:3;1800:11;1791:21;;;;;;;:::i;:::-;;;;1779:6;1786:1;1779:9;;;;;;;;:::i;:::-;;;;:33;;;;;;;;;;-1:-1:-1;1836:1:14;1826:11;;;;;1760:3;;;:::i;:::-;;;1720:128;;;-1:-1:-1;1865:10:14;;1857:55;;;;;;;23569:2:26;1857:55:14;;;23551:21:26;;;23588:18;;;23581:30;23647:34;23627:18;;;23620:62;23699:18;;1857:55:14;23367:356:26;14:196;82:20;;142:42;131:54;;121:65;;111:93;;200:1;197;190:12;111:93;14:196;;;:::o;215:347::-;266:8;276:6;330:3;323:4;315:6;311:17;307:27;297:55;;348:1;345;338:12;297:55;-1:-1:-1;371:20:26;;414:18;403:30;;400:50;;;446:1;443;436:12;400:50;483:4;475:6;471:17;459:29;;535:3;528:4;519:6;511;507:19;503:30;500:39;497:59;;;552:1;549;542:12;497:59;215:347;;;;;:::o;567:758::-;682:6;690;698;706;714;722;730;783:3;771:9;762:7;758:23;754:33;751:53;;;800:1;797;790:12;751:53;823:29;842:9;823:29;:::i;:::-;813:39;;899:2;888:9;884:18;871:32;861:42;;954:2;943:9;939:18;926:32;981:18;973:6;970:30;967:50;;;1013:1;1010;1003:12;967:50;1052:58;1102:7;1093:6;1082:9;1078:22;1052:58;:::i;:::-;567:758;;;;-1:-1:-1;1129:8:26;1211:2;1196:18;;1183:32;;1262:3;1247:19;;1234:33;;-1:-1:-1;1314:3:26;1299:19;;;1286:33;;-1:-1:-1;567:758:26;-1:-1:-1;;;;567:758:26:o;1330:332::-;1388:6;1441:2;1429:9;1420:7;1416:23;1412:32;1409:52;;;1457:1;1454;1447:12;1409:52;1496:9;1483:23;1546:66;1539:5;1535:78;1528:5;1525:89;1515:117;;1628:1;1625;1618:12;2041:689;2147:6;2155;2163;2171;2179;2187;2240:3;2228:9;2219:7;2215:23;2211:33;2208:53;;;2257:1;2254;2247:12;2208:53;2280:29;2299:9;2280:29;:::i;:::-;2270:39;;2356:2;2345:9;2341:18;2328:32;2318:42;;2411:2;2400:9;2396:18;2383:32;2438:18;2430:6;2427:30;2424:50;;;2470:1;2467;2460:12;2424:50;2509:58;2559:7;2550:6;2539:9;2535:22;2509:58;:::i;:::-;2041:689;;;;-1:-1:-1;2586:8:26;2668:2;2653:18;;2640:32;;2719:3;2704:19;;;2691:33;;-1:-1:-1;2041:689:26;-1:-1:-1;;;;2041:689:26:o;2735:180::-;2794:6;2847:2;2835:9;2826:7;2822:23;2818:32;2815:52;;;2863:1;2860;2853:12;2815:52;-1:-1:-1;2886:23:26;;2735:180;-1:-1:-1;2735:180:26:o;2920:184::-;2972:77;2969:1;2962:88;3069:4;3066:1;3059:15;3093:4;3090:1;3083:15;3109:334;3180:2;3174:9;3236:2;3226:13;;3241:66;3222:86;3210:99;;3339:18;3324:34;;3360:22;;;3321:62;3318:88;;;3386:18;;:::i;:::-;3422:2;3415:22;3109:334;;-1:-1:-1;3109:334:26:o;3448:589::-;3490:5;3543:3;3536:4;3528:6;3524:17;3520:27;3510:55;;3561:1;3558;3551:12;3510:55;3597:6;3584:20;3623:18;3619:2;3616:26;3613:52;;;3645:18;;:::i;:::-;3689:114;3797:4;3728:66;3721:4;3717:2;3713:13;3709:86;3705:97;3689:114;:::i;:::-;3828:2;3819:7;3812:19;3874:3;3867:4;3862:2;3854:6;3850:15;3846:26;3843:35;3840:55;;;3891:1;3888;3881:12;3840:55;3956:2;3949:4;3941:6;3937:17;3930:4;3921:7;3917:18;3904:55;4004:1;3979:16;;;3997:4;3975:27;3968:38;;;;3983:7;3448:589;-1:-1:-1;;;3448:589:26:o;4042:537::-;4137:6;4145;4153;4161;4214:3;4202:9;4193:7;4189:23;4185:33;4182:53;;;4231:1;4228;4221:12;4182:53;4254:29;4273:9;4254:29;:::i;:::-;4244:39;;4302:38;4336:2;4325:9;4321:18;4302:38;:::i;:::-;4292:48;;4387:2;4376:9;4372:18;4359:32;4349:42;;4442:2;4431:9;4427:18;4414:32;4469:18;4461:6;4458:30;4455:50;;;4501:1;4498;4491:12;4455:50;4524:49;4565:7;4556:6;4545:9;4541:22;4524:49;:::i;:::-;4514:59;;;4042:537;;;;;;;:::o;4837:254::-;4905:6;4913;4966:2;4954:9;4945:7;4941:23;4937:32;4934:52;;;4982:1;4979;4972:12;4934:52;5018:9;5005:23;4995:33;;5047:38;5081:2;5070:9;5066:18;5047:38;:::i;:::-;5037:48;;4837:254;;;;;:::o;5533:367::-;5596:8;5606:6;5660:3;5653:4;5645:6;5641:17;5637:27;5627:55;;5678:1;5675;5668:12;5627:55;-1:-1:-1;5701:20:26;;5744:18;5733:30;;5730:50;;;5776:1;5773;5766:12;5730:50;5813:4;5805:6;5801:17;5789:29;;5873:3;5866:4;5856:6;5853:1;5849:14;5841:6;5837:27;5833:38;5830:47;5827:67;;;5890:1;5887;5880:12;5905:1306;6101:6;6109;6117;6125;6133;6141;6149;6157;6165;6218:3;6206:9;6197:7;6193:23;6189:33;6186:53;;;6235:1;6232;6225:12;6186:53;6275:9;6262:23;6304:18;6345:2;6337:6;6334:14;6331:34;;;6361:1;6358;6351:12;6331:34;6400:70;6462:7;6453:6;6442:9;6438:22;6400:70;:::i;:::-;6489:8;;-1:-1:-1;6374:96:26;-1:-1:-1;6577:2:26;6562:18;;6549:32;;-1:-1:-1;6593:16:26;;;6590:36;;;6622:1;6619;6612:12;6590:36;6661:72;6725:7;6714:8;6703:9;6699:24;6661:72;:::i;:::-;6752:8;;-1:-1:-1;6635:98:26;-1:-1:-1;6840:2:26;6825:18;;6812:32;;-1:-1:-1;6856:16:26;;;6853:36;;;6885:1;6882;6875:12;6853:36;;6924:72;6988:7;6977:8;6966:9;6962:24;6924:72;:::i;:::-;5905:1306;;;;-1:-1:-1;5905:1306:26;;;;7015:8;;7097:2;7082:18;;7069:32;;7148:3;7133:19;;7120:33;;-1:-1:-1;7200:3:26;7185:19;7172:33;;-1:-1:-1;5905:1306:26;-1:-1:-1;;;;5905:1306:26:o;7216:1237::-;7403:6;7411;7419;7427;7435;7443;7451;7459;7512:3;7500:9;7491:7;7487:23;7483:33;7480:53;;;7529:1;7526;7519:12;7480:53;7569:9;7556:23;7598:18;7639:2;7631:6;7628:14;7625:34;;;7655:1;7652;7645:12;7625:34;7694:70;7756:7;7747:6;7736:9;7732:22;7694:70;:::i;:::-;7783:8;;-1:-1:-1;7668:96:26;-1:-1:-1;7871:2:26;7856:18;;7843:32;;-1:-1:-1;7887:16:26;;;7884:36;;;7916:1;7913;7906:12;7884:36;7955:72;8019:7;8008:8;7997:9;7993:24;7955:72;:::i;:::-;8046:8;;-1:-1:-1;7929:98:26;-1:-1:-1;8134:2:26;8119:18;;8106:32;;-1:-1:-1;8150:16:26;;;8147:36;;;8179:1;8176;8169:12;8147:36;;8218:72;8282:7;8271:8;8260:9;8256:24;8218:72;:::i;:::-;7216:1237;;;;-1:-1:-1;7216:1237:26;;;;8309:8;;8391:2;8376:18;;8363:32;;8442:3;8427:19;8414:33;;-1:-1:-1;7216:1237:26;-1:-1:-1;;;;7216:1237:26:o;8458:712::-;8512:5;8565:3;8558:4;8550:6;8546:17;8542:27;8532:55;;8583:1;8580;8573:12;8532:55;8619:6;8606:20;8645:4;8668:18;8664:2;8661:26;8658:52;;;8690:18;;:::i;:::-;8736:2;8733:1;8729:10;8759:28;8783:2;8779;8775:11;8759:28;:::i;:::-;8821:15;;;8891;;;8887:24;;;8852:12;;;;8923:15;;;8920:35;;;8951:1;8948;8941:12;8920:35;8987:2;8979:6;8975:15;8964:26;;8999:142;9015:6;9010:3;9007:15;8999:142;;;9081:17;;9069:30;;9032:12;;;;9119;;;;8999:142;;;9159:5;8458:712;-1:-1:-1;;;;;;;8458:712:26:o;9175:943::-;9329:6;9337;9345;9353;9361;9414:3;9402:9;9393:7;9389:23;9385:33;9382:53;;;9431:1;9428;9421:12;9382:53;9454:29;9473:9;9454:29;:::i;:::-;9444:39;;9502:38;9536:2;9525:9;9521:18;9502:38;:::i;:::-;9492:48;;9591:2;9580:9;9576:18;9563:32;9614:18;9655:2;9647:6;9644:14;9641:34;;;9671:1;9668;9661:12;9641:34;9694:61;9747:7;9738:6;9727:9;9723:22;9694:61;:::i;:::-;9684:71;;9808:2;9797:9;9793:18;9780:32;9764:48;;9837:2;9827:8;9824:16;9821:36;;;9853:1;9850;9843:12;9821:36;9876:63;9931:7;9920:8;9909:9;9905:24;9876:63;:::i;:::-;9866:73;;9992:3;9981:9;9977:19;9964:33;9948:49;;10022:2;10012:8;10009:16;10006:36;;;10038:1;10035;10028:12;10006:36;;10061:51;10104:7;10093:8;10082:9;10078:24;10061:51;:::i;:::-;10051:61;;;9175:943;;;;;;;;:::o;10305:606::-;10409:6;10417;10425;10433;10441;10494:3;10482:9;10473:7;10469:23;10465:33;10462:53;;;10511:1;10508;10501:12;10462:53;10534:29;10553:9;10534:29;:::i;:::-;10524:39;;10582:38;10616:2;10605:9;10601:18;10582:38;:::i;:::-;10572:48;;10667:2;10656:9;10652:18;10639:32;10629:42;;10718:2;10707:9;10703:18;10690:32;10680:42;;10773:3;10762:9;10758:19;10745:33;10801:18;10793:6;10790:30;10787:50;;;10833:1;10830;10823:12;10787:50;10856:49;10897:7;10888:6;10877:9;10873:22;10856:49;:::i;10916:325::-;11004:6;10999:3;10992:19;11056:6;11049:5;11042:4;11037:3;11033:14;11020:43;;11108:1;11101:4;11092:6;11087:3;11083:16;11079:27;11072:38;10974:3;11230:4;11160:66;11155:2;11147:6;11143:15;11139:88;11134:3;11130:98;11126:109;11119:116;;10916:325;;;;:::o;11246:580::-;11527:42;11519:6;11515:55;11504:9;11497:74;11607:6;11602:2;11591:9;11587:18;11580:34;11650:3;11645:2;11634:9;11630:18;11623:31;11478:4;11671:62;11728:3;11717:9;11713:19;11705:6;11697;11671:62;:::i;:::-;11764:2;11749:18;;11742:34;;;;-1:-1:-1;11807:3:26;11792:19;11785:35;11663:70;11246:580;-1:-1:-1;;;;11246:580:26:o;11831:435::-;12056:42;12048:6;12044:55;12033:9;12026:74;12136:6;12131:2;12120:9;12116:18;12109:34;12179:2;12174;12163:9;12159:18;12152:30;12007:4;12199:61;12256:2;12245:9;12241:18;12233:6;12225;12199:61;:::i;:::-;12191:69;11831:435;-1:-1:-1;;;;;;11831:435:26:o;14341:184::-;14393:77;14390:1;14383:88;14490:4;14487:1;14480:15;14514:4;14511:1;14504:15;14530:186;14589:6;14642:2;14630:9;14621:7;14617:23;14613:32;14610:52;;;14658:1;14655;14648:12;14610:52;14681:29;14700:9;14681:29;:::i;14721:580::-;14798:4;14804:6;14864:11;14851:25;14954:66;14943:8;14927:14;14923:29;14919:102;14899:18;14895:127;14885:155;;15036:1;15033;15026:12;14885:155;15063:33;;15115:20;;;-1:-1:-1;15158:18:26;15147:30;;15144:50;;;15190:1;15187;15180:12;15144:50;15223:4;15211:17;;-1:-1:-1;15254:14:26;15250:27;;;15240:38;;15237:58;;;15291:1;15288;15281:12;15306:184;15358:77;15355:1;15348:88;15455:4;15452:1;15445:15;15479:4;15476:1;15469:15;15495:195;15534:3;15565:66;15558:5;15555:77;15552:103;;15635:18;;:::i;:::-;-1:-1:-1;15682:1:26;15671:13;;15495:195::o;15695:1126::-;15802:6;15797:3;15790:19;15772:3;15828:4;15869:2;15864:3;15860:12;15894:11;15921;15914:18;;15971:6;15968:1;15964:14;15957:5;15953:26;15941:38;;16002:5;16025:1;16035:760;16049:6;16046:1;16043:13;16035:760;;;16120:5;16114:4;16110:16;16105:3;16098:29;16179:6;16166:20;16265:66;16257:5;16241:14;16237:26;16233:99;16213:18;16209:124;16199:152;;16347:1;16344;16337:12;16199:152;16379:30;;16487:16;;;;16438:21;16532:18;16519:32;;16516:52;;;16564:1;16561;16554:12;16516:52;16617:8;16601:14;16597:29;16588:7;16584:43;16581:63;;;16640:1;16637;16630:12;16581:63;16665:50;16710:4;16700:8;16691:7;16665:50;:::i;:::-;16773:12;;;;16657:58;-1:-1:-1;;;16738:15:26;;;;16071:1;16064:9;16035:760;;;-1:-1:-1;16811:4:26;;15695:1126;-1:-1:-1;;;;;;;15695:1126:26:o;16826:1463::-;17278:3;17291:22;;;17263:19;;17348:22;;;17230:4;17428:6;17401:3;17386:19;;17230:4;17462:258;17476:6;17473:1;17470:13;17462:258;;;17569:42;17541:26;17560:6;17541:26;:::i;:::-;17537:75;17525:88;;17636:4;17695:15;;;;17660:12;;;;17498:1;17491:9;17462:258;;;17466:3;17767:9;17762:3;17758:19;17751:4;17740:9;17736:20;17729:49;17799:6;17794:3;17787:19;17829:66;17821:6;17818:78;17815:98;;;17909:1;17906;17899:12;17815:98;17943:6;17940:1;17936:14;17922:28;;17996:6;17988;17981:4;17976:3;17972:14;17959:44;18022:16;18078:18;;;18098:4;18074:29;;;18069:2;18054:18;;18047:57;18121:75;;18182:13;;18174:6;18166;18121:75;:::i;:::-;18227:2;18212:18;;18205:34;;;;-1:-1:-1;;18270:3:26;18255:19;18248:35;18113:83;16826:1463;-1:-1:-1;;;;;;16826:1463:26:o;18712:277::-;18779:6;18832:2;18820:9;18811:7;18807:23;18803:32;18800:52;;;18848:1;18845;18838:12;18800:52;18880:9;18874:16;18933:5;18926:13;18919:21;18912:5;18909:32;18899:60;;18955:1;18952;18945:12;19817:125;19882:9;;;19903:10;;;19900:36;;;19916:18;;:::i;19947:250::-;20032:1;20042:113;20056:6;20053:1;20050:13;20042:113;;;20132:11;;;20126:18;20113:11;;;20106:39;20078:2;20071:10;20042:113;;;-1:-1:-1;;20189:1:26;20171:16;;20164:27;19947:250::o;20202:812::-;20613:25;20608:3;20601:38;20583:3;20668:6;20662:13;20684:75;20752:6;20747:2;20742:3;20738:12;20731:4;20723:6;20719:17;20684:75;:::i;:::-;20823:19;20818:2;20778:16;;;20810:11;;;20803:40;20868:13;;20890:76;20868:13;20952:2;20944:11;;20937:4;20925:17;;20890:76;:::i;:::-;20986:17;21005:2;20982:26;;20202:812;-1:-1:-1;;;;20202:812:26:o;21019:455::-;21168:2;21157:9;21150:21;21131:4;21200:6;21194:13;21243:6;21238:2;21227:9;21223:18;21216:34;21259:79;21331:6;21326:2;21315:9;21311:18;21306:2;21298:6;21294:15;21259:79;:::i;:::-;21390:2;21378:15;21395:66;21374:88;21359:104;;;;21465:2;21355:113;;21019:455;-1:-1:-1;;21019:455:26:o;22297:271::-;22480:6;22472;22467:3;22454:33;22436:3;22506:16;;22531:13;;;22506:16;22297:271;-1:-1:-1;22297:271:26:o;22993:168::-;23066:9;;;23097;;23114:15;;;23108:22;;23094:37;23084:71;;23135:18;;:::i;23166:196::-;23205:3;23233:5;23223:39;;23242:18;;:::i;:::-;-1:-1:-1;23289:66:26;23278:78;;23166:196::o
Swarm Source
ipfs://e28ae7494480ab1c619fd775dc5ff665588c808a910d66178a982c2e7c76a1e6

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.