Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- PolygonRollupManagerNotUpgraded
- Optimization enabled
- true
- Compiler version
- v0.8.20+commit.a1b79de6
- Optimization runs
- 200
- EVM Version
- paris
- Verified at
- 2025-09-29T07:13:01.407463Z
Constructor Arguments
0x000000000000000000000000dbd32f81789bf2395d24d646a07a41639d9955fb000000000000000000000000429a1ed765b18e78f068e98e5ab1212a21aa131400000000000000000000000094a5c76eb7ab1ecd1ca43d637f9fc12b68a495d7
Arg [0] (address) : 0xdbd32f81789bf2395d24d646a07a41639d9955fb
Arg [1] (address) : 0x429a1ed765b18e78f068e98e5ab1212a21aa1314
Arg [2] (address) : 0x94a5c76eb7ab1ecd1ca43d637f9fc12b68a495d7
contracts/v2/newDeployments/PolygonRollupManagerNotUpgraded.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.20;
import "../PolygonRollupManager.sol";
/**
* PolygonRollupManager Test
*/
contract PolygonRollupManagerNotUpgraded is PolygonRollupManager {
/**
* @param _globalExitRootManager Global exit root manager address
* @param _pol MATIC token address
* @param _bridgeAddress Bridge address
*/
constructor(
IPolygonZkEVMGlobalExitRootV2 _globalExitRootManager,
IERC20Upgradeable _pol,
IPolygonZkEVMBridge _bridgeAddress
) PolygonRollupManager(_globalExitRootManager, _pol, _bridgeAddress) {}
function initialize(
address trustedAggregator,
uint64 _pendingStateTimeout,
uint64 _trustedAggregatorTimeout,
address admin,
address timelock,
address emergencyCouncil,
PolygonZkEVMExistentEtrog /*polygonZkEVM*/,
IVerifierRollup /*zkEVMVerifier*/,
uint64 /*zkEVMForkID*/,
uint64 /*zkEVMChainID*/
) external reinitializer(2) {
pendingStateTimeout = _pendingStateTimeout;
trustedAggregatorTimeout = _trustedAggregatorTimeout;
// Constant deployment variables
_batchFee = 0.1 ether; // 0.1 Matic
verifyBatchTimeTarget = 30 minutes;
multiplierBatchFee = 1002;
// Initialize OZ contracts
__AccessControl_init();
// setup roles
// trusted aggregator role
_setupRole(_TRUSTED_AGGREGATOR_ROLE, trustedAggregator);
// Timelock roles
_setupRole(DEFAULT_ADMIN_ROLE, timelock);
_setupRole(_ADD_ROLLUP_TYPE_ROLE, timelock);
_setupRole(_ADD_EXISTING_ROLLUP_ROLE, timelock);
// Even this role can only update to an already added verifier/consensus
// Could break the compatibility of them, changing the virtual state
_setupRole(_UPDATE_ROLLUP_ROLE, timelock);
// Admin roles
_setupRole(_OBSOLETE_ROLLUP_TYPE_ROLE, admin);
_setupRole(_CREATE_ROLLUP_ROLE, admin);
_setupRole(_STOP_EMERGENCY_ROLE, admin);
_setupRole(_TWEAK_PARAMETERS_ROLE, admin);
_setRoleAdmin(_TRUSTED_AGGREGATOR_ROLE, _TRUSTED_AGGREGATOR_ROLE_ADMIN);
_setupRole(_TRUSTED_AGGREGATOR_ROLE_ADMIN, admin);
_setupRole(_SET_FEE_ROLE, admin);
// Emergency council roles
_setRoleAdmin(_EMERGENCY_COUNCIL_ROLE, _EMERGENCY_COUNCIL_ADMIN);
_setupRole(_EMERGENCY_COUNCIL_ROLE, emergencyCouncil);
_setupRole(_EMERGENCY_COUNCIL_ADMIN, emergencyCouncil);
}
}
contracts/interfaces/IBasePolygonZkEVMGlobalExitRoot.sol
// 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);
}
contracts/v2/interfaces/IPolygonZkEVMGlobalExitRootV2.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
import "../../interfaces/IBasePolygonZkEVMGlobalExitRoot.sol";
interface IPolygonZkEVMGlobalExitRootV2 is IBasePolygonZkEVMGlobalExitRoot {
function getLastGlobalExitRoot() external view returns (bytes32);
function getRoot() external view returns (bytes32);
function l1InfoRootMap(
uint32 depositCount
) external view returns (bytes32);
}
contracts/v2/lib/PolygonConstantsBase.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
/**
* This contract will contain the constants used across different contracts
*/
contract PolygonConstantsBase {
// If the system a does not verify a batch inside this time window, 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;
}
contracts/lib/EmergencyManager.sol
// 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();
}
}
@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol
// 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);
}
}
}
contracts/v2/lib/LegacyZKEVMStateVariables.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
/**
* Since the current contract of PolygonZkEVM will be upgraded to a PolygonRollupManager there's defined
* all the legacy public variables in order to not use previous used storage slots
* The variables will be used by the RollupManager only for initialize the zkEVM inside the initializer function
*/
contract LegacyZKEVMStateVariables {
/**
* @notice Struct which will be stored for every batch sequence
* @param accInputHash Hash chain that contains all the information to process a batch:
* Before etrog: keccak256(bytes32 oldAccInputHash, keccak256(bytes transactions), bytes32 globalExitRoot, uint64 timestamp, address seqAddress)
* Etrog: keccak256(bytes32 oldAccInputHash, keccak256(bytes transactions), bytes32 l1InfoRoot/forcedGlobalExitRoot, uint64 currentTimestamp/forcedTimestamp, address l2Coinbase, bytes32 0/forcedBlockHashL1)
* @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;
}
// Time target of the verification of a batch
// Adaptatly the batchFee will be updated to achieve this target
/// @custom:oz-renamed-from verifyBatchTimeTarget
uint64 internal _legacyVerifyBatchTimeTarget;
// Batch fee multiplier with 3 decimals that goes from 1000 - 1023
/// @custom:oz-renamed-from multiplierBatchFee
uint16 internal _legacyMultiplierBatchFee;
// Trusted sequencer address
/// @custom:oz-renamed-from trustedSequencer
address internal _legacyTrustedSequencer;
// Current matic fee per batch sequenced
/// @custom:oz-renamed-from batchFee
uint256 internal _legacyBatchFee;
// 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)
/// @custom:oz-renamed-from forcedBatches
mapping(uint64 => bytes32) internal _legacyForcedBatches;
// Queue of batches that defines the virtual state
// SequenceBatchNum --> SequencedBatchData
/// @custom:oz-renamed-from sequencedBatches
mapping(uint64 => SequencedBatchData) internal _legacySequencedBatches;
// Last sequenced timestamp
/// @custom:oz-renamed-from lastTimestamp
uint64 internal _legacyLastTimestamp;
// Last batch sent by the sequencers
/// @custom:oz-renamed-from lastBatchSequenced
uint64 internal _legacylastBatchSequenced;
// Last forced batch included in the sequence
/// @custom:oz-renamed-from lastForceBatchSequenced
uint64 internal _legacyLastForceBatchSequenced;
// Last forced batch
/// @custom:oz-renamed-from lastForceBatch
uint64 internal _legacyLastForceBatch;
// Last batch verified by the aggregators
/// @custom:oz-renamed-from lastVerifiedBatch
uint64 internal _legacyLastVerifiedBatch;
// Trusted aggregator address
/// @custom:oz-renamed-from trustedAggregator
address internal _legacyTrustedAggregator;
// State root mapping
// BatchNum --> state root
/// @custom:oz-renamed-from batchNumToStateRoot
mapping(uint64 => bytes32) internal _legacyBatchNumToStateRoot;
// Trusted sequencer URL
/// @custom:oz-renamed-from trustedSequencerURL
string internal _legacyTrustedSequencerURL;
// L2 network name
/// @custom:oz-renamed-from networkName
string internal _legacyNetworkName;
// Pending state mapping
// pendingStateNumber --> PendingState
/// @custom:oz-renamed-from pendingStateTransitions
mapping(uint256 => PendingState) internal _legacyPendingStateTransitions;
// Last pending state
/// @custom:oz-renamed-from lastPendingState
uint64 internal _legacyLastPendingState;
// Last pending state consolidated
/// @custom:oz-renamed-from lastPendingStateConsolidated
uint64 internal _legacyLastPendingStateConsolidated;
// Once a pending state exceeds this timeout it can be consolidated
/// @custom:oz-renamed-from pendingStateTimeout
uint64 internal _legacyPendingStateTimeout;
// Trusted aggregator timeout, if a sequence is not verified in this time frame,
// everyone can verify that sequence
/// @custom:oz-renamed-from trustedAggregatorTimeout
uint64 internal _legacyTrustedAggregatorTimeout;
// Address that will be able to adjust contract parameters or stop the emergency state
/// @custom:oz-renamed-from admin
address internal _legacyAdmin;
// This account will be able to accept the admin role
/// @custom:oz-renamed-from pendingAdmin
address internal _legacyPendingAdmin;
// Force batch timeout
/// @custom:oz-renamed-from forceBatchTimeout
uint64 internal _legacyForceBatchTimeout;
// Indicates if forced batches are disallowed
/// @custom:oz-renamed-from isForcedBatchDisallowed
bool internal _legacyIsForcedBatchDisallowed;
// Indicates the current version
/// @custom:oz-renamed-from version
uint256 internal _legacyVersion;
// Last batch verified before the last upgrade
/// @custom:oz-renamed-from lastVerifiedBatchBeforeUpgrade
uint256 internal _legacyLastVerifiedBatchBeforeUpgrade;
}
@openzeppelin/contracts5/proxy/Proxy.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Proxy.sol)
pragma solidity ^0.8.20;
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
* be specified by overriding the virtual {_implementation} function.
*
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
* different contract through the {_delegate} function.
*
* The success and return data of the delegated call will be returned back to the caller of the proxy.
*/
abstract contract Proxy {
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal virtual {
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
/**
* @dev This is a virtual function that should be overridden so it returns the address to which the fallback
* function and {_fallback} should delegate.
*/
function _implementation() internal view virtual returns (address);
/**
* @dev Delegates the current call to the address returned by `_implementation()`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _fallback() internal virtual {
_delegate(_implementation());
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
* function in the contract matches the call data.
*/
fallback() external payable virtual {
_fallback();
}
}
@openzeppelin/contracts-upgradeable/access/IAccessControlUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControlUpgradeable {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}
contracts/v2/consensus/zkEVM/PolygonZkEVMExistentEtrog.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.20;
import "../../lib/PolygonRollupBaseEtrog.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 PolygonZkEVMExistentEtrog is PolygonRollupBaseEtrog {
// Transaction that will be injected as a forced transaction, to setup the timestamp on the state root, we just need a well encoded RLP transaction
// It's ok if the transaction is not processable
/* Encoded transaction:
{
"from": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D",
"to": "0x4d5Cf5032B2a844602278b01199ED191A86c93ff",
"nonce": 42,
"data": "0x",
"value": "0",
"gasLimit": 0,
"gasPrice": "0",
"chainId": 4242,
"overwrite": {
"v": "0x1b",
"r": "0x00000000000000000000000000000000000000000000000000000005ca1ab1e0",
"s": "0x00000000000000000000000000000000000000000000000000000005ca1ab1e0"
}
}
*/
bytes public constant SET_UP_ETROG_TX =
hex"df2a8080944d5cf5032b2a844602278b01199ed191a86c93ff8080821092808000000000000000000000000000000000000000000000000000000005ca1ab1e000000000000000000000000000000000000000000000000000000005ca1ab1e01bff";
/**
* @dev Emitted when the system is updated to a etrog using this contract, contain the set up etrog transaction
*/
event UpdateEtrogSequence(
uint64 numBatch,
bytes transactions,
bytes32 lastGlobalExitRoot,
address sequencer
);
/**
* @param _globalExitRootManager Global exit root manager address
* @param _pol POL token address
* @param _bridgeAddress Bridge address
* @param _rollupManager Global exit root manager address
*/
constructor(
IPolygonZkEVMGlobalExitRootV2 _globalExitRootManager,
IERC20Upgradeable _pol,
IPolygonZkEVMBridgeV2 _bridgeAddress,
PolygonRollupManager _rollupManager
)
PolygonRollupBaseEtrog(
_globalExitRootManager,
_pol,
_bridgeAddress,
_rollupManager
)
{}
/**
* note This initializer will be called instead of the PolygonRollupBase
* This is a especial initializer since the zkEVM it's an already created network
* @param _admin Admin address
* @param _trustedSequencer Trusted sequencer address
* @param _trustedSequencerURL Trusted sequencer URL
* @param _networkName L2 network name
* @param _lastAccInputHash Acc input hash
*/
function initializeUpgrade(
address _admin,
address _trustedSequencer,
string memory _trustedSequencerURL,
string memory _networkName,
bytes32 _lastAccInputHash
) external onlyRollupManager initializer {
// Set up etrog Tx
bytes memory transaction = SET_UP_ETROG_TX;
bytes32 currentTransactionsHash = keccak256(transaction);
// Get current timestamp and global exit root
uint64 currentTimestamp = uint64(block.timestamp);
bytes32 lastGlobalExitRoot = globalExitRootManager
.getLastGlobalExitRoot();
// Add the transaction to the sequence as if it was a force transaction
bytes32 newAccInputHash = keccak256(
abi.encodePacked(
_lastAccInputHash, // Last acc Input hash
currentTransactionsHash,
lastGlobalExitRoot, // Global exit root
currentTimestamp,
_trustedSequencer,
blockhash(block.number - 1)
)
);
// Set acumulated input hash
lastAccInputHash = newAccInputHash;
uint64 currentBatchSequenced = rollupManager.onSequenceBatches(
uint64(1), // num total batches
newAccInputHash
);
// Set zkEVM variables
admin = _admin;
trustedSequencer = _trustedSequencer;
trustedSequencerURL = _trustedSequencerURL;
networkName = _networkName;
forceBatchAddress = _admin;
// Constant variables
forceBatchTimeout = 5 days;
// Both gasTokenAddress and gasTokenNetwork are 0, since it uses ether as gas token
// Therefore is not necessary to set the variables
emit UpdateEtrogSequence(
currentBatchSequenced,
transaction,
lastGlobalExitRoot,
_trustedSequencer
);
}
}
@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-IERC20PermitUpgradeable.sol
// 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);
}
@openzeppelin/contracts5/proxy/ERC1967/ERC1967Utils.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol)
pragma solidity ^0.8.20;
import {IBeacon} from "../beacon/IBeacon.sol";
import {Address} from "../../utils/Address.sol";
import {StorageSlot} from "../../utils/StorageSlot.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*/
library ERC1967Utils {
// We re-declare ERC-1967 events here because they can't be used directly from IERC1967.
// This will be fixed in Solidity 0.8.21. At that point we should remove these events.
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev The `implementation` of the proxy is invalid.
*/
error ERC1967InvalidImplementation(address implementation);
/**
* @dev The `admin` of the proxy is invalid.
*/
error ERC1967InvalidAdmin(address admin);
/**
* @dev The `beacon` of the proxy is invalid.
*/
error ERC1967InvalidBeacon(address beacon);
/**
* @dev An upgrade function sees `msg.value > 0` that may be lost.
*/
error ERC1967NonPayable();
/**
* @dev Returns the current implementation address.
*/
function getImplementation() internal view returns (address) {
return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
if (newImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(newImplementation);
}
StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Performs implementation upgrade with additional setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-Upgraded} event.
*/
function upgradeToAndCall(address newImplementation, bytes memory data) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
if (data.length > 0) {
Address.functionDelegateCall(newImplementation, data);
} else {
_checkNonPayable();
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
* the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103`
*/
function getAdmin() internal view returns (address) {
return StorageSlot.getAddressSlot(ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
if (newAdmin == address(0)) {
revert ERC1967InvalidAdmin(address(0));
}
StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {IERC1967-AdminChanged} event.
*/
function changeAdmin(address newAdmin) internal {
emit AdminChanged(getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1.
*/
// solhint-disable-next-line private-vars-leading-underscore
bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function getBeacon() internal view returns (address) {
return StorageSlot.getAddressSlot(BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
if (newBeacon.code.length == 0) {
revert ERC1967InvalidBeacon(newBeacon);
}
StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon;
address beaconImplementation = IBeacon(newBeacon).implementation();
if (beaconImplementation.code.length == 0) {
revert ERC1967InvalidImplementation(beaconImplementation);
}
}
/**
* @dev Change the beacon and trigger a setup call if data is nonempty.
* This function is payable only if the setup call is performed, otherwise `msg.value` is rejected
* to avoid stuck value in the contract.
*
* Emits an {IERC1967-BeaconUpgraded} event.
*
* CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since
* it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for
* efficiency.
*/
function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0) {
Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
} else {
_checkNonPayable();
}
}
/**
* @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract
* if an upgrade doesn't perform an initialization call.
*/
function _checkNonPayable() private {
if (msg.value > 0) {
revert ERC1967NonPayable();
}
}
}
@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20Upgradeable.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20MetadataUpgradeable is IERC20Upgradeable {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
contracts/v2/interfaces/IPolygonZkEVMVEtrogErrors.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
import "../../interfaces/IPolygonZkEVMErrors.sol";
interface IPolygonZkEVMVEtrogErrors is IPolygonZkEVMErrors {
/**
* @dev Thrown when the caller is not the trusted sequencer
*/
error OnlyRollupManager();
/**
* @dev Thrown when the caller is not the trusted sequencer
*/
error NotEnoughPOLAmount();
/**
* @dev Thrown when the caller is not the trusted sequencer
*/
error InvalidInitializeTransaction();
/**
* @dev Thrown when the caller is not the trusted sequencer
*/
error GasTokenNetworkMustBeZeroOnEther();
/**
* @dev Thrown when the try to initialize with a gas token with huge metadata
*/
error HugeTokenMetadataNotSupported();
/**
* @dev Thrown when trying force a batch during emergency state
*/
error ForceBatchesNotAllowedOnEmergencyState();
/**
* @dev Thrown when the try to sequence force batches before the halt timeout period
*/
error HaltTimeoutNotExpiredAfterEmergencyState();
/**
* @dev Thrown when the try to update the force batch address once is set to address(0)
*/
error ForceBatchesDecentralized();
/**
* @dev Thrown when the last sequenced batch nmber does not match the init sequeced batch number
*/
error InitSequencedBatchDoesNotMatch();
/**
* @dev Thrown when the max timestamp is out of range
*/
error MaxTimestampSequenceInvalid();
/**
* @dev Thrown when l1 info tree leafCount does not exist
*/
error L1InfoTreeLeafCountInvalid();
/**
* @dev Thrown when the acc input hash does not match the predicted by the sequencer
*/
error FinalAccInputHashDoesNotMatch();
}
contracts/v2/interfaces/IPolygonZkEVMBridgeV2.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
import "../../interfaces/IBasePolygonZkEVMGlobalExitRoot.sol";
interface IPolygonZkEVMBridgeV2 {
/**
* @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();
/**
* @dev Thrown when sender is not the rollup manager
*/
error OnlyRollupManager();
/**
* @dev Thrown when the permit data contains an invalid signature
*/
error NativeTokenIsEther();
/**
* @dev Thrown when the permit data contains an invalid signature
*/
error NoValueInMessagesOnGasTokenNetworks();
/**
* @dev Thrown when the permit data contains an invalid signature
*/
error GasTokenNetworkMustBeZeroOnEther();
/**
* @dev Thrown when the wrapped token deployment fails
*/
error FailedTokenWrappedDeployment();
function wrappedTokenToTokenInfo(
address destinationAddress
) external view returns (uint32, address);
function updateGlobalExitRoot() external;
function activateEmergencyState() external;
function deactivateEmergencyState() external;
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 bridgeMessageWETH(
uint32 destinationNetwork,
address destinationAddress,
uint256 amountWETH,
bool forceUpdateGlobalExitRoot,
bytes calldata metadata
) external;
function claimAsset(
bytes32[32] calldata smtProofLocalExitRoot,
bytes32[32] calldata smtProofRollupExitRoot,
uint256 globalIndex,
bytes32 mainnetExitRoot,
bytes32 rollupExitRoot,
uint32 originNetwork,
address originTokenAddress,
uint32 destinationNetwork,
address destinationAddress,
uint256 amount,
bytes calldata metadata
) external;
function claimMessage(
bytes32[32] calldata smtProofLocalExitRoot,
bytes32[32] calldata smtProofRollupExitRoot,
uint256 globalIndex,
bytes32 mainnetExitRoot,
bytes32 rollupExitRoot,
uint32 originNetwork,
address originAddress,
uint32 destinationNetwork,
address destinationAddress,
uint256 amount,
bytes calldata metadata
) external;
function initialize(
uint32 _networkID,
address _gasTokenAddress,
uint32 _gasTokenNetwork,
IBasePolygonZkEVMGlobalExitRoot _globalExitRootManager,
address _polygonRollupManager,
bytes memory _gasTokenMetadata
) external;
function getTokenMetadata(
address token
) external view returns (bytes memory);
}
@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol
// 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;
}
}
contracts/interfaces/IVerifierRollup.sol
// 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);
}
@openzeppelin/contracts5/proxy/transparent/ProxyAdmin.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/ProxyAdmin.sol)
pragma solidity ^0.8.20;
import {ITransparentUpgradeableProxy} from "./TransparentUpgradeableProxy.sol";
import {Ownable} from "../../access/Ownable.sol";
/**
* @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an
* explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}.
*/
contract ProxyAdmin is Ownable {
/**
* @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgrade(address)`
* and `upgradeAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called,
* while `upgradeAndCall` will invoke the `receive` function if the second argument is the empty byte string.
* If the getter returns `"5.0.0"`, only `upgradeAndCall(address,bytes)` is present, and the second argument must
* be the empty byte string if no function should be called, making it impossible to invoke the `receive` function
* during an upgrade.
*/
string public constant UPGRADE_INTERFACE_VERSION = "5.0.0";
/**
* @dev Sets the initial owner who can perform upgrades.
*/
constructor(address initialOwner) Ownable(initialOwner) {}
/**
* @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation.
* See {TransparentUpgradeableProxy-_dispatchUpgradeToAndCall}.
*
* Requirements:
*
* - This contract must be the admin of `proxy`.
* - If `data` is empty, `msg.value` must be zero.
*/
function upgradeAndCall(
ITransparentUpgradeableProxy proxy,
address implementation,
bytes memory data
) public payable virtual onlyOwner {
proxy.upgradeToAndCall{value: msg.value}(implementation, data);
}
}
@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/MathUpgradeable.sol";
/**
* @dev String operations.
*/
library StringsUpgradeable {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = MathUpgradeable.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, MathUpgradeable.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
}
@openzeppelin/contracts5/utils/StorageSlot.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}
contracts/v2/lib/PolygonTransparentProxy.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/TransparentUpgradeableProxy.sol)
pragma solidity ^0.8.20;
import {ERC1967Utils} from "@openzeppelin/contracts5/proxy/ERC1967/ERC1967Utils.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts5/proxy/ERC1967/ERC1967Proxy.sol";
import {IERC1967} from "@openzeppelin/contracts5/interfaces/IERC1967.sol";
import {ProxyAdmin} from "@openzeppelin/contracts5/proxy/transparent/ProxyAdmin.sol";
import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts5/proxy/transparent/TransparentUpgradeableProxy.sol";
/**
* @dev Contrac TransparentUpgradeableProxy from Openzeppelin v5 with the following modifications:
* - Admin is a parameter in the constructor ( like previous versions) isntead of being deployed
* - Let the admin get access to the proxy
* - Replace _msgSender() with msg.sender
*/
contract PolygonTransparentProxy is ERC1967Proxy {
// An immutable address for the admin to avoid unnecessary SLOADs before each call
// at the expense of removing the ability to change the admin once it's set.
// This is acceptable if the admin is always a ProxyAdmin instance or similar contract
// with its own ability to transfer the permissions to another account.
address private immutable _admin;
/**
* @dev Initializes an upgradeable proxy managed by an instance of a {ProxyAdmin} with an `initialOwner`,
* backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in
* {ERC1967Proxy-constructor}.
*/
constructor(
address _logic,
address admin,
bytes memory _data
) payable ERC1967Proxy(_logic, _data) {
_admin = admin;
// Set the storage value and emit an event for ERC-1967 compatibility
ERC1967Utils.changeAdmin(_proxyAdmin());
}
/**
* @dev Returns the admin of this proxy.
*/
function _proxyAdmin() internal virtual returns (address) {
return _admin;
}
/**
* @dev If caller is the admin process the call internally, otherwise transparently fallback to the proxy behavior.
*/
function _fallback() internal virtual override {
if (msg.sender == _proxyAdmin()) {
if (
msg.sig !=
ITransparentUpgradeableProxy.upgradeToAndCall.selector
) {
super._fallback();
} else {
_dispatchUpgradeToAndCall();
}
} else {
super._fallback();
}
}
/**
* @dev Upgrade the implementation of the proxy. See {ERC1967Utils-upgradeToAndCall}.
*
* Requirements:
*
* - If `data` is empty, `msg.value` must be zero.
*/
function _dispatchUpgradeToAndCall() private {
(address newImplementation, bytes memory data) = abi.decode(
msg.data[4:],
(address, bytes)
);
ERC1967Utils.upgradeToAndCall(newImplementation, data);
}
}
contracts/interfaces/IPolygonZkEVMErrors.sol
// 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();
}
@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165Upgradeable {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol
// 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);
}
contracts/v2/PolygonRollupManager.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.20;
import "./interfaces/IPolygonRollupManager.sol";
import "./interfaces/IPolygonZkEVMGlobalExitRootV2.sol";
import "../interfaces/IPolygonZkEVMBridge.sol";
import "./interfaces/IPolygonRollupBase.sol";
import "../interfaces/IVerifierRollup.sol";
import "../lib/EmergencyManager.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import "./lib/PolygonTransparentProxy.sol";
import "./lib/PolygonAccessControlUpgradeable.sol";
import "./lib/LegacyZKEVMStateVariables.sol";
import "./consensus/zkEVM/PolygonZkEVMExistentEtrog.sol";
import "./lib/PolygonConstantsBase.sol";
/**
* Contract responsible for managing rollups and the verification of their batches.
* This contract will create and update rollups and store all the hashed sequenced data from them.
* The logic for sequence batches is moved to the `consensus` contracts, while the verification of all of
* them will be done in this one. In this way, the proof aggregation of the rollups will be easier on a close future.
*/
contract PolygonRollupManager is
PolygonAccessControlUpgradeable,
EmergencyManager,
LegacyZKEVMStateVariables,
PolygonConstantsBase,
IPolygonRollupManager
{
using SafeERC20Upgradeable for IERC20Upgradeable;
/**
* @notice Struct which to store the rollup type data
* @param consensusImplementation Consensus implementation ( contains the consensus logic for the transaparent proxy)
* @param verifier verifier
* @param forkID fork ID
* @param rollupCompatibilityID Rollup compatibility ID, to check upgradability between rollup types
* @param obsolete Indicates if the rollup type is obsolete
* @param genesis Genesis block of the rollup, note that will only be used on creating new rollups, not upgrade them
*/
struct RollupType {
address consensusImplementation;
IVerifierRollup verifier;
uint64 forkID;
uint8 rollupCompatibilityID;
bool obsolete;
bytes32 genesis;
}
/**
* @notice Struct which to store the rollup data of each chain
* @param rollupContract Rollup consensus contract, which manages everything
* related to sequencing transactions
* @param chainID Chain ID of the rollup
* @param verifier Verifier contract
* @param forkID ForkID of the rollup
* @param batchNumToStateRoot State root mapping
* @param sequencedBatches Queue of batches that defines the virtual state
* @param pendingStateTransitions Pending state mapping
* @param lastLocalExitRoot Last exit root verified, used for compute the rollupExitRoot
* @param lastBatchSequenced Last batch sent by the consensus contract
* @param lastVerifiedBatch Last batch verified
* @param lastPendingState Last pending state
* @param lastPendingStateConsolidated Last pending state consolidated
* @param lastVerifiedBatchBeforeUpgrade Last batch verified before the last upgrade
* @param rollupTypeID Rollup type ID, can be 0 if it was added as an existing rollup
* @param rollupCompatibilityID Rollup ID used for compatibility checks when upgrading
*/
struct RollupData {
IPolygonRollupBase rollupContract;
uint64 chainID;
IVerifierRollup verifier;
uint64 forkID;
mapping(uint64 batchNum => bytes32) batchNumToStateRoot;
mapping(uint64 batchNum => SequencedBatchData) sequencedBatches;
mapping(uint256 pendingStateNum => PendingState) pendingStateTransitions;
bytes32 lastLocalExitRoot;
uint64 lastBatchSequenced;
uint64 lastVerifiedBatch;
uint64 lastPendingState;
uint64 lastPendingStateConsolidated;
uint64 lastVerifiedBatchBeforeUpgrade;
uint64 rollupTypeID;
uint8 rollupCompatibilityID;
}
// Modulus zkSNARK
uint256 internal constant _RFIELD =
21888242871839275222246405745257275088548364400416034343698204186575808495617;
// 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
// Exit merkle tree levels
uint256 internal constant _EXIT_TREE_DEPTH = 32;
// Roles
// Be able to add a new rollup type
bytes32 internal constant _ADD_ROLLUP_TYPE_ROLE =
keccak256("ADD_ROLLUP_TYPE_ROLE");
// Be able to obsolete a rollup type, which means that new rollups cannot use this type
bytes32 internal constant _OBSOLETE_ROLLUP_TYPE_ROLE =
keccak256("OBSOLETE_ROLLUP_TYPE_ROLE");
// Be able to create a new rollup using a rollup type
bytes32 internal constant _CREATE_ROLLUP_ROLE =
keccak256("CREATE_ROLLUP_ROLE");
// Be able to create a new rollup which does not have to follow any rollup type.
// Also sets the genesis block for that network
bytes32 internal constant _ADD_EXISTING_ROLLUP_ROLE =
keccak256("ADD_EXISTING_ROLLUP_ROLE");
// Be able to update a rollup to a new rollup type that it's compatible
bytes32 internal constant _UPDATE_ROLLUP_ROLE =
keccak256("UPDATE_ROLLUP_ROLE");
// Be able to that has priority to verify batches and consolidates the state instantly
bytes32 internal constant _TRUSTED_AGGREGATOR_ROLE =
keccak256("TRUSTED_AGGREGATOR_ROLE");
// Be able to set the trusted aggregator address
bytes32 internal constant _TRUSTED_AGGREGATOR_ROLE_ADMIN =
keccak256("TRUSTED_AGGREGATOR_ROLE_ADMIN");
// Be able to tweak parameters
bytes32 internal constant _TWEAK_PARAMETERS_ROLE =
keccak256("TWEAK_PARAMETERS_ROLE");
// Be able to set the current batch fee
bytes32 internal constant _SET_FEE_ROLE = keccak256("SET_FEE_ROLE");
// Be able to stop the emergency state
bytes32 internal constant _STOP_EMERGENCY_ROLE =
keccak256("STOP_EMERGENCY_ROLE");
// Be able to activate the emergency state without any further condition
bytes32 internal constant _EMERGENCY_COUNCIL_ROLE =
keccak256("EMERGENCY_COUNCIL_ROLE");
// Be able to set the emergency council address
bytes32 internal constant _EMERGENCY_COUNCIL_ADMIN =
keccak256("EMERGENCY_COUNCIL_ADMIN");
// Global Exit Root address
IPolygonZkEVMGlobalExitRootV2 public immutable globalExitRootManager;
// PolygonZkEVM Bridge Address
IPolygonZkEVMBridge public immutable bridgeAddress;
// POL token address
IERC20Upgradeable public immutable pol;
// Number of rollup types added, every new type will be assigned sequencially a new ID
uint32 public rollupTypeCount;
// Rollup type mapping
mapping(uint32 rollupTypeID => RollupType) public rollupTypeMap;
// Number of rollups added, every new rollup will be assigned sequencially a new ID
uint32 public rollupCount;
// Rollups ID mapping
mapping(uint32 rollupID => RollupData) public rollupIDToRollupData;
// Rollups address mapping
mapping(address rollupAddress => uint32 rollupID) public rollupAddressToID;
// Chain ID mapping for nullifying
// note we will take care to avoid that current known chainIDs are not reused in our networks (example: 1)
mapping(uint64 chainID => uint32 rollupID) public chainIDToRollupID;
// Total sequenced batches across all rollups
uint64 public totalSequencedBatches;
// Total verified batches across all rollups
uint64 public totalVerifiedBatches;
// Last timestamp when an aggregation happen
uint64 public lastAggregationTimestamp;
// Trusted aggregator timeout, if a sequence is not verified in this time frame,
// everyone can verify that sequence
uint64 public trustedAggregatorTimeout;
// Once a pending state exceeds this timeout it can be consolidated
uint64 public pendingStateTimeout;
// Time target of the verification of a batch
// Adaptively 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;
// Current POL fee per batch sequenced
// note This variable is internal, since the view function getBatchFee is likely to be upgraded
uint256 internal _batchFee;
// Timestamp when the last emergency state was deactivated
uint64 public lastDeactivatedEmergencyStateTimestamp;
/**
* @dev Emitted when a new rollup type is added
*/
event AddNewRollupType(
uint32 indexed rollupTypeID,
address consensusImplementation,
address verifier,
uint64 forkID,
uint8 rollupCompatibilityID,
bytes32 genesis,
string description
);
/**
* @dev Emitted when a a rolup type is obsoleted
*/
event ObsoleteRollupType(uint32 indexed rollupTypeID);
/**
* @dev Emitted when a new rollup is created based on a rollupType
*/
event CreateNewRollup(
uint32 indexed rollupID,
uint32 rollupTypeID,
address rollupAddress,
uint64 chainID,
address gasTokenAddress
);
/**
* @dev Emitted when an existing rollup is added
*/
event AddExistingRollup(
uint32 indexed rollupID,
uint64 forkID,
address rollupAddress,
uint64 chainID,
uint8 rollupCompatibilityID,
uint64 lastVerifiedBatchBeforeUpgrade
);
/**
* @dev Emitted when a rollup is udpated
*/
event UpdateRollup(
uint32 indexed rollupID,
uint32 newRollupTypeID,
uint64 lastVerifiedBatchBeforeUpgrade
);
/**
* @dev Emitted when a new verifier is added
*/
event OnSequenceBatches(uint32 indexed rollupID, uint64 lastBatchSequenced);
/**
* @dev Emitted when an aggregator verifies batches
*/
event VerifyBatches(
uint32 indexed rollupID,
uint64 numBatch,
bytes32 stateRoot,
bytes32 exitRoot,
address indexed aggregator
);
/**
* @dev Emitted when the trusted aggregator verifies batches
*/
event VerifyBatchesTrustedAggregator(
uint32 indexed rollupID,
uint64 numBatch,
bytes32 stateRoot,
bytes32 exitRoot,
address indexed aggregator
);
/**
* @dev Emitted when pending state is consolidated
*/
event ConsolidatePendingState(
uint32 indexed rollupID,
uint64 numBatch,
bytes32 stateRoot,
bytes32 exitRoot,
uint64 pendingStateNum
);
/**
* @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(
uint32 indexed rollupID,
uint64 numBatch,
bytes32 stateRoot,
bytes32 exitRoot,
address aggregator
);
/**
* @dev Emitted when rollback batches
*/
event RollbackBatches(
uint32 indexed rollupID,
uint64 indexed targetBatch,
bytes32 accInputHashToRollback
);
/**
* @dev Emitted when is updated the trusted aggregator timeout
*/
event SetTrustedAggregatorTimeout(uint64 newTrustedAggregatorTimeout);
/**
* @dev Emitted when is updated the pending state timeout
*/
event SetPendingStateTimeout(uint64 newPendingStateTimeout);
/**
* @dev Emitted when is updated the multiplier batch fee
*/
event SetMultiplierBatchFee(uint16 newMultiplierBatchFee);
/**
* @dev Emitted when is updated the verify batch timeout
*/
event SetVerifyBatchTimeTarget(uint64 newVerifyBatchTimeTarget);
/**
* @dev Emitted when is updated the trusted aggregator address
*/
event SetTrustedAggregator(address newTrustedAggregator);
/**
* @dev Emitted when is updated the batch fee
*/
event SetBatchFee(uint256 newBatchFee);
/**
* @param _globalExitRootManager Global exit root manager address
* @param _pol POL token address
* @param _bridgeAddress Bridge address
*/
constructor(
IPolygonZkEVMGlobalExitRootV2 _globalExitRootManager,
IERC20Upgradeable _pol,
IPolygonZkEVMBridge _bridgeAddress
) {
globalExitRootManager = _globalExitRootManager;
pol = _pol;
bridgeAddress = _bridgeAddress;
// Disable initalizers on the implementation following the best practices
_disableInitializers();
}
///////////////////////////////////////
// Rollups management functions
///////////////////////////////////////
/**
* @notice Add a new rollup type
* @param consensusImplementation Consensus implementation
* @param verifier Verifier address
* @param forkID ForkID of the verifier
* @param genesis Genesis block of the rollup
* @param description Description of the rollup type
*/
function addNewRollupType(
address consensusImplementation,
IVerifierRollup verifier,
uint64 forkID,
uint8 rollupCompatibilityID,
bytes32 genesis,
string memory description
) external onlyRole(_ADD_ROLLUP_TYPE_ROLE) {
uint32 rollupTypeID = ++rollupTypeCount;
rollupTypeMap[rollupTypeID] = RollupType({
consensusImplementation: consensusImplementation,
verifier: verifier,
forkID: forkID,
rollupCompatibilityID: rollupCompatibilityID,
obsolete: false,
genesis: genesis
});
emit AddNewRollupType(
rollupTypeID,
consensusImplementation,
address(verifier),
forkID,
rollupCompatibilityID,
genesis,
description
);
}
/**
* @notice Obsolete Rollup type
* @param rollupTypeID Rollup type to obsolete
*/
function obsoleteRollupType(
uint32 rollupTypeID
) external onlyRole(_OBSOLETE_ROLLUP_TYPE_ROLE) {
// Check that rollup type exists
if (rollupTypeID == 0 || rollupTypeID > rollupTypeCount) {
revert RollupTypeDoesNotExist();
}
// Check rollup type is not obsolete
RollupType storage currentRollupType = rollupTypeMap[rollupTypeID];
if (currentRollupType.obsolete == true) {
revert RollupTypeObsolete();
}
currentRollupType.obsolete = true;
emit ObsoleteRollupType(rollupTypeID);
}
/**
* @notice Create a new rollup
* @param rollupTypeID Rollup type to deploy
* @param chainID ChainID of the rollup, must be a new one, can not have more than 32 bits
* @param admin Admin of the new created rollup
* @param sequencer Sequencer of the new created rollup
* @param gasTokenAddress Indicates the token address that will be used to pay gas fees in the new rollup
* Note if a wrapped token of the bridge is used, the original network and address of this wrapped will be used instead
* @param sequencerURL Sequencer URL of the new created rollup
* @param networkName Network name of the new created rollup
*/
function createNewRollup(
uint32 rollupTypeID,
uint64 chainID,
address admin,
address sequencer,
address gasTokenAddress,
string memory sequencerURL,
string memory networkName
) external onlyRole(_CREATE_ROLLUP_ROLE) {
// Check that rollup type exists
if (rollupTypeID == 0 || rollupTypeID > rollupTypeCount) {
revert RollupTypeDoesNotExist();
}
// Check rollup type is not obsolete
RollupType storage rollupType = rollupTypeMap[rollupTypeID];
if (rollupType.obsolete == true) {
revert RollupTypeObsolete();
}
// check chainID max value
// Currently we have this limitation by the circuit, might be removed in a future
if (chainID > type(uint32).max) {
revert ChainIDOutOfRange();
}
// Check chainID nullifier
if (chainIDToRollupID[chainID] != 0) {
revert ChainIDAlreadyExist();
}
// Create a new Rollup, using a transparent proxy pattern
// Consensus will be the implementation, and this contract the admin
uint32 rollupID = ++rollupCount;
address rollupAddress = address(
new PolygonTransparentProxy(
rollupType.consensusImplementation,
address(this),
new bytes(0)
)
);
// Set chainID nullifier
chainIDToRollupID[chainID] = rollupID;
// Store rollup data
rollupAddressToID[rollupAddress] = rollupID;
RollupData storage rollup = rollupIDToRollupData[rollupID];
rollup.rollupContract = IPolygonRollupBase(rollupAddress);
rollup.forkID = rollupType.forkID;
rollup.verifier = rollupType.verifier;
rollup.chainID = chainID;
rollup.batchNumToStateRoot[0] = rollupType.genesis;
rollup.rollupTypeID = rollupTypeID;
rollup.rollupCompatibilityID = rollupType.rollupCompatibilityID;
emit CreateNewRollup(
rollupID,
rollupTypeID,
rollupAddress,
chainID,
gasTokenAddress
);
// Initialize new rollup
IPolygonRollupBase(rollupAddress).initialize(
admin,
sequencer,
rollupID,
gasTokenAddress,
sequencerURL,
networkName
);
}
/**
* @notice Add an already deployed rollup
* note that this rollup does not follow any rollupType
* @param rollupAddress Rollup address
* @param verifier Verifier address, must be added before
* @param forkID Fork id of the added rollup
* @param chainID Chain id of the added rollup
* @param genesis Genesis block for this rollup
* @param rollupCompatibilityID Compatibility ID for the added rollup
*/
function addExistingRollup(
IPolygonRollupBase rollupAddress,
IVerifierRollup verifier,
uint64 forkID,
uint64 chainID,
bytes32 genesis,
uint8 rollupCompatibilityID
) external onlyRole(_ADD_EXISTING_ROLLUP_ROLE) {
// Check chainID nullifier
if (chainIDToRollupID[chainID] != 0) {
revert ChainIDAlreadyExist();
}
// check chainID max value
// Currently we have this limitation by the circuit, might be removed in a future
if (chainID > type(uint32).max) {
revert ChainIDOutOfRange();
}
// Check if rollup address was already added
if (rollupAddressToID[address(rollupAddress)] != 0) {
revert RollupAddressAlreadyExist();
}
RollupData storage rollup = _addExistingRollup(
rollupAddress,
verifier,
forkID,
chainID,
rollupCompatibilityID
);
rollup.batchNumToStateRoot[0] = genesis;
}
/**
* @notice Add an already deployed rollup
* note that this rollup does not follow any rollupType
* @param rollupAddress Rollup address
* @param verifier Verifier address, must be added before
* @param forkID Fork id of the added rollup
* @param chainID Chain id of the added rollup
* @param rollupCompatibilityID Compatibility ID for the added rollup
*/
function _addExistingRollup(
IPolygonRollupBase rollupAddress,
IVerifierRollup verifier,
uint64 forkID,
uint64 chainID,
uint8 rollupCompatibilityID
) internal returns (RollupData storage rollup) {
uint32 rollupID = ++rollupCount;
// Set chainID nullifier
chainIDToRollupID[chainID] = rollupID;
// Store rollup data
rollupAddressToID[address(rollupAddress)] = rollupID;
rollup = rollupIDToRollupData[rollupID];
rollup.rollupContract = rollupAddress;
rollup.forkID = forkID;
rollup.verifier = verifier;
rollup.chainID = chainID;
rollup.rollupCompatibilityID = rollupCompatibilityID;
// rollup type is 0, since it does not follow any rollup type
emit AddExistingRollup(
rollupID,
forkID,
address(rollupAddress),
chainID,
rollupCompatibilityID,
0
);
}
/**
* @notice Upgrade an existing rollup from the rollup admin address
* This address is able to udpate the rollup with more restrictions that the _UPDATE_ROLLUP_ROLE
* @param rollupContract Rollup consensus proxy address
* @param newRollupTypeID New rolluptypeID to upgrade to
*/
function updateRollupByRollupAdmin(
ITransparentUpgradeableProxy rollupContract,
uint32 newRollupTypeID
) external {
// Check admin of the network is msg.sender
if (IPolygonRollupBase(address(rollupContract)).admin() != msg.sender) {
revert OnlyRollupAdmin();
}
// Check all sequences are verified before upgrading
RollupData storage rollup = rollupIDToRollupData[
rollupAddressToID[address(rollupContract)]
];
// Check all sequenced batches are verified
if (rollup.lastBatchSequenced != rollup.lastVerifiedBatch) {
revert AllSequencedMustBeVerified();
}
// review sanity check
if (rollup.rollupTypeID >= newRollupTypeID) {
revert UpdateToOldRollupTypeID();
}
_updateRollup(rollupContract, newRollupTypeID, new bytes(0));
}
/**
* @notice Upgrade an existing rollup
* @param rollupContract Rollup consensus proxy address
* @param newRollupTypeID New rolluptypeID to upgrade to
* @param upgradeData Upgrade data
*/
function updateRollup(
ITransparentUpgradeableProxy rollupContract,
uint32 newRollupTypeID,
bytes memory upgradeData
) external onlyRole(_UPDATE_ROLLUP_ROLE) {
_updateRollup(rollupContract, newRollupTypeID, upgradeData);
}
/**
* @notice Upgrade an existing rollup
* @param rollupContract Rollup consensus proxy address
* @param newRollupTypeID New rolluptypeID to upgrade to
* @param upgradeData Upgrade data
*/
function _updateRollup(
ITransparentUpgradeableProxy rollupContract,
uint32 newRollupTypeID,
bytes memory upgradeData
) internal {
// Check that rollup type exists
if (newRollupTypeID == 0 || newRollupTypeID > rollupTypeCount) {
revert RollupTypeDoesNotExist();
}
// Check the rollup exists
uint32 rollupID = rollupAddressToID[address(rollupContract)];
if (rollupID == 0) {
revert RollupMustExist();
}
RollupData storage rollup = rollupIDToRollupData[rollupID];
// The update must be to a new rollup type
if (rollup.rollupTypeID == newRollupTypeID) {
revert UpdateToSameRollupTypeID();
}
RollupType storage newRollupType = rollupTypeMap[newRollupTypeID];
// Check rollup type is not obsolete
if (newRollupType.obsolete == true) {
revert RollupTypeObsolete();
}
// Check compatibility of the rollups
if (
rollup.rollupCompatibilityID != newRollupType.rollupCompatibilityID
) {
revert UpdateNotCompatible();
}
// Update rollup parameters
rollup.verifier = newRollupType.verifier;
rollup.forkID = newRollupType.forkID;
rollup.rollupTypeID = newRollupTypeID;
// review fix to vulnerability front running attack
if (rollup.lastPendingState != rollup.lastPendingStateConsolidated) {
revert CannotUpdateWithUnconsolidatedPendingState();
}
uint64 lastVerifiedBatch = getLastVerifiedBatch(rollupID);
rollup.lastVerifiedBatchBeforeUpgrade = lastVerifiedBatch;
// Upgrade rollup
rollupContract.upgradeToAndCall(
newRollupType.consensusImplementation,
upgradeData
);
emit UpdateRollup(rollupID, newRollupTypeID, lastVerifiedBatch);
}
/**
* @notice Rollback batches of the target rollup
* @param rollupContract Rollup consensus proxy address
* @param targetBatch Batch to rollback up to but not including this batch
*/
function rollbackBatches(
IPolygonRollupBase rollupContract,
uint64 targetBatch
) external {
// Check msg.sender has _UPDATE_ROLLUP_ROLE rol or is the admin of the network
if (
!hasRole(_UPDATE_ROLLUP_ROLE, msg.sender) &&
IPolygonRollupBase(address(rollupContract)).admin() != msg.sender
) {
revert NotAllowedAddress();
}
// Check the rollup exists
uint32 rollupID = rollupAddressToID[address(rollupContract)];
if (rollupID == 0) {
revert RollupMustExist();
}
// Load rollup
RollupData storage rollup = rollupIDToRollupData[rollupID];
uint64 lastBatchSequenced = rollup.lastBatchSequenced;
// Batch to rollback should be already sequenced
if (
targetBatch >= lastBatchSequenced ||
targetBatch < rollup.lastVerifiedBatch
) {
revert RollbackBatchIsNotValid();
}
uint64 currentBatch = lastBatchSequenced;
// delete sequence batches structs until the targetBatch
while (currentBatch != targetBatch) {
// Load previous end of sequence batch
uint64 previousBatch = rollup
.sequencedBatches[currentBatch]
.previousLastBatchSequenced;
// Batch to rollback must be end of a sequence
if (previousBatch < targetBatch) {
revert RollbackBatchIsNotEndOfSequence();
}
// delete sequence information
delete rollup.sequencedBatches[currentBatch];
// Update current batch for next iteration
currentBatch = previousBatch;
}
// Update last batch sequenced on rollup data
rollup.lastBatchSequenced = targetBatch;
// Update totalSequencedBatches
totalSequencedBatches -= lastBatchSequenced - targetBatch;
// Check pending state
if (rollup.lastPendingState > 0) {
// update total verified batches
uint64 currentLastVerifiedBatch = _getLastVerifiedBatch(rollup);
totalVerifiedBatches -=
currentLastVerifiedBatch -
rollup.lastVerifiedBatch;
rollup.lastPendingState = 0;
rollup.lastPendingStateConsolidated = 0;
}
// Clean pending state if any
rollupContract.rollbackBatches(
targetBatch,
rollup.sequencedBatches[targetBatch].accInputHash
);
emit RollbackBatches(
rollupID,
targetBatch,
rollup.sequencedBatches[targetBatch].accInputHash
);
}
/////////////////////////////////////
// Sequence/Verify batches functions
////////////////////////////////////
/**
* @notice Sequence batches, callback called by one of the consensus managed by this contract
* @param newSequencedBatches Number of batches sequenced
* @param newAccInputHash New accumulate input hash
*/
function onSequenceBatches(
uint64 newSequencedBatches,
bytes32 newAccInputHash
) external ifNotEmergencyState returns (uint64) {
// Check that the msg.sender is an added rollup
uint32 rollupID = rollupAddressToID[msg.sender];
if (rollupID == 0) {
revert SenderMustBeRollup();
}
// This prevents overwritting sequencedBatches
if (newSequencedBatches == 0) {
revert MustSequenceSomeBatch();
}
RollupData storage rollup = rollupIDToRollupData[rollupID];
// Update total sequence parameters
totalSequencedBatches += newSequencedBatches;
// Update sequenced batches of the current rollup
uint64 previousLastBatchSequenced = rollup.lastBatchSequenced;
uint64 newLastBatchSequenced = previousLastBatchSequenced +
newSequencedBatches;
rollup.lastBatchSequenced = newLastBatchSequenced;
rollup.sequencedBatches[newLastBatchSequenced] = SequencedBatchData({
accInputHash: newAccInputHash,
sequencedTimestamp: uint64(block.timestamp),
previousLastBatchSequenced: previousLastBatchSequenced
});
// Consolidate pending state if possible
_tryConsolidatePendingState(rollup);
emit OnSequenceBatches(rollupID, newLastBatchSequenced);
return newLastBatchSequenced;
}
/**
* @notice Allows an aggregator to verify multiple batches
* @param rollupID Rollup identifier
* @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 beneficiary Address that will receive the verification reward
* @param proof Fflonk proof
*/
function verifyBatches(
uint32 rollupID,
uint64 pendingStateNum,
uint64 initNumBatch,
uint64 finalNewBatch,
bytes32 newLocalExitRoot,
bytes32 newStateRoot,
address beneficiary,
bytes32[24] calldata proof
) external ifNotEmergencyState {
RollupData storage rollup = rollupIDToRollupData[rollupID];
// Check if the trusted aggregator timeout expired,
// Note that the sequencedBatches struct must exists for this finalNewBatch, if not newAccInputHash will be 0
if (
rollup.sequencedBatches[finalNewBatch].sequencedTimestamp +
trustedAggregatorTimeout >
block.timestamp
) {
revert TrustedAggregatorTimeoutNotExpired();
}
if (finalNewBatch - initNumBatch > _MAX_VERIFY_BATCHES) {
revert ExceedMaxVerifyBatches();
}
_verifyAndRewardBatches(
rollup,
pendingStateNum,
initNumBatch,
finalNewBatch,
newLocalExitRoot,
newStateRoot,
beneficiary,
proof
);
// Update batch fees
_updateBatchFee(rollup, finalNewBatch);
if (pendingStateTimeout == 0) {
// Consolidate state
rollup.lastVerifiedBatch = finalNewBatch;
rollup.batchNumToStateRoot[finalNewBatch] = newStateRoot;
rollup.lastLocalExitRoot = newLocalExitRoot;
// Clean pending state if any
if (rollup.lastPendingState > 0) {
rollup.lastPendingState = 0;
rollup.lastPendingStateConsolidated = 0;
}
// Interact with globalExitRootManager
globalExitRootManager.updateExitRoot(getRollupExitRoot());
} else {
// Consolidate pending state if possible
_tryConsolidatePendingState(rollup);
// Update pending state
rollup.lastPendingState++;
rollup.pendingStateTransitions[
rollup.lastPendingState
] = PendingState({
timestamp: uint64(block.timestamp),
lastVerifiedBatch: finalNewBatch,
exitRoot: newLocalExitRoot,
stateRoot: newStateRoot
});
}
emit VerifyBatches(
rollupID,
finalNewBatch,
newStateRoot,
newLocalExitRoot,
msg.sender
);
}
/**
* @notice Allows a trusted aggregator to verify multiple batches
* @param rollupID Rollup identifier
* @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 beneficiary Address that will receive the verification reward
* @param proof Fflonk proof
*/
function verifyBatchesTrustedAggregator(
uint32 rollupID,
uint64 pendingStateNum,
uint64 initNumBatch,
uint64 finalNewBatch,
bytes32 newLocalExitRoot,
bytes32 newStateRoot,
address beneficiary,
bytes32[24] calldata proof
) external onlyRole(_TRUSTED_AGGREGATOR_ROLE) {
RollupData storage rollup = rollupIDToRollupData[rollupID];
_verifyAndRewardBatches(
rollup,
pendingStateNum,
initNumBatch,
finalNewBatch,
newLocalExitRoot,
newStateRoot,
beneficiary,
proof
);
// Consolidate state
rollup.lastVerifiedBatch = finalNewBatch;
rollup.batchNumToStateRoot[finalNewBatch] = newStateRoot;
rollup.lastLocalExitRoot = newLocalExitRoot;
// Clean pending state if any
if (rollup.lastPendingState > 0) {
rollup.lastPendingState = 0;
rollup.lastPendingStateConsolidated = 0;
}
// Interact with globalExitRootManager
globalExitRootManager.updateExitRoot(getRollupExitRoot());
emit VerifyBatchesTrustedAggregator(
rollupID,
finalNewBatch,
newStateRoot,
newLocalExitRoot,
msg.sender
);
}
/**
* @notice Verify and reward batches internal function
* @param rollup Rollup Data storage pointer that will be used to the verification
* @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 beneficiary Address that will receive the verification reward
* @param proof Fflonk proof
*/
function _verifyAndRewardBatches(
RollupData storage rollup,
uint64 pendingStateNum,
uint64 initNumBatch,
uint64 finalNewBatch,
bytes32 newLocalExitRoot,
bytes32 newStateRoot,
address beneficiary,
bytes32[24] calldata proof
) internal virtual {
bytes32 oldStateRoot;
uint64 currentLastVerifiedBatch = _getLastVerifiedBatch(rollup);
if (initNumBatch < rollup.lastVerifiedBatchBeforeUpgrade) {
revert InitBatchMustMatchCurrentForkID();
}
// 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 > rollup.lastPendingState) {
revert PendingStateDoesNotExist();
}
// Check choosen pending state
PendingState storage currentPendingState = rollup
.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 = rollup.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(
rollup,
initNumBatch,
finalNewBatch,
newLocalExitRoot,
oldStateRoot,
newStateRoot
);
// Calulate the snark input
uint256 inputSnark = uint256(sha256(snarkHashBytes)) % _RFIELD;
// Verify proof
if (!rollup.verifier.verifyProof(proof, [inputSnark])) {
revert InvalidProof();
}
// Pay POL rewards
uint64 newVerifiedBatches = finalNewBatch - currentLastVerifiedBatch;
pol.safeTransfer(
beneficiary,
calculateRewardPerBatch() * newVerifiedBatches
);
// Update aggregation parameters
totalVerifiedBatches += newVerifiedBatches;
lastAggregationTimestamp = uint64(block.timestamp);
// Callback to the rollup address
rollup.rollupContract.onVerifyBatches(
finalNewBatch,
newStateRoot,
msg.sender
);
}
/**
* @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(RollupData storage rollup) internal {
// Check if there's any state to consolidate
if (rollup.lastPendingState > rollup.lastPendingStateConsolidated) {
// Check if it's possible to consolidate the next pending state
uint64 nextPendingState = rollup.lastPendingStateConsolidated + 1;
if (_isPendingStateConsolidable(rollup, nextPendingState)) {
// Check middle pending state ( binary search of 1 step)
uint64 middlePendingState = nextPendingState +
(rollup.lastPendingState - nextPendingState) /
2;
// Try to consolidate it, and if not, consolidate the nextPendingState
if (_isPendingStateConsolidable(rollup, middlePendingState)) {
_consolidatePendingState(rollup, middlePendingState);
} else {
_consolidatePendingState(rollup, 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 rollupID Rollup identifier
* @param pendingStateNum Pending state to consolidate
*/
function consolidatePendingState(
uint32 rollupID,
uint64 pendingStateNum
) external {
RollupData storage rollup = rollupIDToRollupData[rollupID];
// Check if pending state can be consolidated
// If trusted aggregator is the sender, do not check the timeout or the emergency state
if (!hasRole(_TRUSTED_AGGREGATOR_ROLE, msg.sender)) {
if (isEmergencyState) {
revert OnlyNotEmergencyState();
}
if (!_isPendingStateConsolidable(rollup, pendingStateNum)) {
revert PendingStateNotConsolidable();
}
}
_consolidatePendingState(rollup, pendingStateNum);
}
/**
* @notice Internal function to consolidate any pending state that has already exceed the pendingStateTimeout
* @param rollup Rollup data storage pointer
* @param pendingStateNum Pending state to consolidate
*/
function _consolidatePendingState(
RollupData storage rollup,
uint64 pendingStateNum
) internal {
// Check if pendingStateNum is in correct range
// - not consolidated (implicity checks that is not 0)
// - exist ( has been added)
if (
pendingStateNum <= rollup.lastPendingStateConsolidated ||
pendingStateNum > rollup.lastPendingState
) {
revert PendingStateInvalid();
}
PendingState storage currentPendingState = rollup
.pendingStateTransitions[pendingStateNum];
// Update state
uint64 newLastVerifiedBatch = currentPendingState.lastVerifiedBatch;
rollup.lastVerifiedBatch = newLastVerifiedBatch;
rollup.batchNumToStateRoot[newLastVerifiedBatch] = currentPendingState
.stateRoot;
rollup.lastLocalExitRoot = currentPendingState.exitRoot;
// Update pending state
rollup.lastPendingStateConsolidated = pendingStateNum;
// Interact with globalExitRootManager
globalExitRootManager.updateExitRoot(getRollupExitRoot());
emit ConsolidatePendingState(
rollupAddressToID[address(rollup.rollupContract)],
newLastVerifiedBatch,
currentPendingState.stateRoot,
currentPendingState.exitRoot,
pendingStateNum
);
}
/////////////////////////////////
// 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 rollupID Rollup identifier
* @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(
uint32 rollupID,
uint64 initPendingStateNum,
uint64 finalPendingStateNum,
uint64 initNumBatch,
uint64 finalNewBatch,
bytes32 newLocalExitRoot,
bytes32 newStateRoot,
bytes32[24] calldata proof
) external onlyRole(_TRUSTED_AGGREGATOR_ROLE) {
RollupData storage rollup = rollupIDToRollupData[rollupID];
_proveDistinctPendingState(
rollup,
initPendingStateNum,
finalPendingStateNum,
initNumBatch,
finalNewBatch,
newLocalExitRoot,
newStateRoot,
proof
);
// Consolidate state
rollup.lastVerifiedBatch = finalNewBatch;
rollup.batchNumToStateRoot[finalNewBatch] = newStateRoot;
rollup.lastLocalExitRoot = newLocalExitRoot;
// Clean pending state if any
if (rollup.lastPendingState > 0) {
rollup.lastPendingState = 0;
rollup.lastPendingStateConsolidated = 0;
}
// Interact with globalExitRootManager
globalExitRootManager.updateExitRoot(getRollupExitRoot());
// Update trusted aggregator timeout to max
trustedAggregatorTimeout = _HALT_AGGREGATION_TIMEOUT;
emit OverridePendingState(
rollupID,
finalNewBatch,
newStateRoot,
newLocalExitRoot,
msg.sender
);
}
/**
* @notice Allows activate the emergency state if its possible to prove a different state root given the same batches
* @param rollupID Rollup identifier
* @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(
uint32 rollupID,
uint64 initPendingStateNum,
uint64 finalPendingStateNum,
uint64 initNumBatch,
uint64 finalNewBatch,
bytes32 newLocalExitRoot,
bytes32 newStateRoot,
bytes32[24] calldata proof
) external ifNotEmergencyState {
RollupData storage rollup = rollupIDToRollupData[rollupID];
_proveDistinctPendingState(
rollup,
initPendingStateNum,
finalPendingStateNum,
initNumBatch,
finalNewBatch,
newLocalExitRoot,
newStateRoot,
proof
);
emit ProveNonDeterministicPendingState(
rollup.pendingStateTransitions[finalPendingStateNum].stateRoot,
newStateRoot
);
// Activate emergency state
_activateEmergencyState();
}
/**
* @notice Internal function that proves a different state root given the same batches to verify
* @param rollup Rollup Data struct that will be checked
* @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(
RollupData storage rollup,
uint64 initPendingStateNum,
uint64 finalPendingStateNum,
uint64 initNumBatch,
uint64 finalNewBatch,
bytes32 newLocalExitRoot,
bytes32 newStateRoot,
bytes32[24] calldata proof
) internal view virtual {
bytes32 oldStateRoot;
if (initNumBatch < rollup.lastVerifiedBatchBeforeUpgrade) {
revert InitBatchMustMatchCurrentForkID();
}
// 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 > rollup.lastPendingState) {
revert PendingStateDoesNotExist();
}
// Check choosen pending state
PendingState storage initPendingState = rollup
.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 = rollup.batchNumToStateRoot[initNumBatch];
if (oldStateRoot == bytes32(0)) {
revert OldStateRootDoesNotExist();
}
// Check initNumBatch is inside the range, sanity check
if (initNumBatch > rollup.lastVerifiedBatch) {
revert InitNumBatchAboveLastVerifiedBatch();
}
}
// Assert final pending state num is in correct range
// - exist ( has been added)
// - bigger than the initPendingstate
// - not consolidated
if (
finalPendingStateNum > rollup.lastPendingState ||
finalPendingStateNum <= initPendingStateNum ||
finalPendingStateNum <= rollup.lastPendingStateConsolidated
) {
revert FinalPendingStateNumInvalid();
}
// Check final num batch
if (
finalNewBatch !=
rollup
.pendingStateTransitions[finalPendingStateNum]
.lastVerifiedBatch
) {
revert FinalNumBatchDoesNotMatchPendingState();
}
// Get snark bytes
bytes memory snarkHashBytes = _getInputSnarkBytes(
rollup,
initNumBatch,
finalNewBatch,
newLocalExitRoot,
oldStateRoot,
newStateRoot
);
// Calulate the snark input
uint256 inputSnark = uint256(sha256(snarkHashBytes)) % _RFIELD;
// Verify proof
if (!rollup.verifier.verifyProof(proof, [inputSnark])) {
revert InvalidProof();
}
if (
rollup.pendingStateTransitions[finalPendingStateNum].stateRoot ==
newStateRoot
) {
revert StoredRootMustBeDifferentThanNewRoot();
}
}
/**
* @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(
RollupData storage rollup,
uint64 newLastVerifiedBatch
) internal {
uint64 currentLastVerifiedBatch = _getLastVerifiedBatch(rollup);
uint64 currentBatch = newLastVerifiedBatch;
uint256 totalBatchesAboveTarget;
uint256 newBatchesVerified = newLastVerifiedBatch -
currentLastVerifiedBatch;
uint256 targetTimestamp = block.timestamp - verifyBatchTimeTarget;
while (currentBatch != currentLastVerifiedBatch) {
// Load sequenced batchdata
SequencedBatchData storage currentSequencedBatchData = rollup
.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;
}
}
////////////////////////
// Emergency state functions
////////////////////////
/**
* @notice Function to activate emergency state, which also enables the emergency mode on both PolygonRollupManager and PolygonZkEVMBridge contracts
* If not called by the owner must not have been aggregated in a _HALT_AGGREGATION_TIMEOUT period and an emergency state was not happened in the same period
*/
function activateEmergencyState() external {
if (!hasRole(_EMERGENCY_COUNCIL_ROLE, msg.sender)) {
if (
lastAggregationTimestamp == 0 ||
lastAggregationTimestamp + _HALT_AGGREGATION_TIMEOUT >
block.timestamp ||
lastDeactivatedEmergencyStateTimestamp +
_HALT_AGGREGATION_TIMEOUT >
block.timestamp
) {
revert HaltTimeoutNotExpired();
}
}
_activateEmergencyState();
}
/**
* @notice Function to deactivate emergency state on both PolygonRollupManager and PolygonZkEVMBridge contracts
*/
function deactivateEmergencyState()
external
onlyRole(_STOP_EMERGENCY_ROLE)
{
// Set last deactivated emergency state
lastDeactivatedEmergencyStateTimestamp = uint64(block.timestamp);
// Deactivate emergency state on PolygonZkEVMBridge
bridgeAddress.deactivateEmergencyState();
// Deactivate emergency state on this contract
super._deactivateEmergencyState();
}
/**
* @notice Internal function to activate emergency state on both PolygonRollupManager and PolygonZkEVMBridge contracts
*/
function _activateEmergencyState() internal override {
// Activate emergency state on PolygonZkEVM Bridge
bridgeAddress.activateEmergencyState();
// Activate emergency state on this contract
super._activateEmergencyState();
}
//////////////////
// Setter functions
//////////////////
/**
* @notice 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 onlyRole(_TWEAK_PARAMETERS_ROLE) {
if (!isEmergencyState) {
if (newTrustedAggregatorTimeout >= trustedAggregatorTimeout) {
revert NewTrustedAggregatorTimeoutMustBeLower();
}
}
trustedAggregatorTimeout = newTrustedAggregatorTimeout;
emit SetTrustedAggregatorTimeout(newTrustedAggregatorTimeout);
}
/**
* @notice 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 onlyRole(_TWEAK_PARAMETERS_ROLE) {
if (!isEmergencyState) {
if (newPendingStateTimeout >= pendingStateTimeout) {
revert NewPendingStateTimeoutMustBeLower();
}
}
pendingStateTimeout = newPendingStateTimeout;
emit SetPendingStateTimeout(newPendingStateTimeout);
}
/**
* @notice Set a new multiplier batch fee
* @param newMultiplierBatchFee multiplier batch fee
*/
function setMultiplierBatchFee(
uint16 newMultiplierBatchFee
) external onlyRole(_TWEAK_PARAMETERS_ROLE) {
if (newMultiplierBatchFee < 1000 || newMultiplierBatchFee > 1023) {
revert InvalidRangeMultiplierBatchFee();
}
multiplierBatchFee = newMultiplierBatchFee;
emit SetMultiplierBatchFee(newMultiplierBatchFee);
}
/**
* @notice 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 onlyRole(_TWEAK_PARAMETERS_ROLE) {
if (newVerifyBatchTimeTarget > 1 days) {
revert InvalidRangeBatchTimeTarget();
}
verifyBatchTimeTarget = newVerifyBatchTimeTarget;
emit SetVerifyBatchTimeTarget(newVerifyBatchTimeTarget);
}
/**
* @notice Set the current batch fee
* @param newBatchFee new batch fee
*/
function setBatchFee(uint256 newBatchFee) external onlyRole(_SET_FEE_ROLE) {
// check fees min and max
if (newBatchFee > _MAX_BATCH_FEE || newBatchFee < _MIN_BATCH_FEE) {
revert BatchFeeOutOfRange();
}
_batchFee = newBatchFee;
emit SetBatchFee(newBatchFee);
}
////////////////////////
// view/pure functions
///////////////////////
/**
* @notice Get the current rollup exit root
* Compute using all the local exit roots of all rollups the rollup exit root
* Since it's expected to have no more than 10 rollups in this first version, even if this approach
* has a gas consumption that scales linearly with the rollups added, it's ok
* In a future versions this computation will be done inside the circuit
*/
function getRollupExitRoot() public view returns (bytes32) {
uint256 currentNodes = rollupCount;
// If there are no nodes return 0
if (currentNodes == 0) {
return bytes32(0);
}
// This array will contain the nodes of the current iteration
bytes32[] memory tmpTree = new bytes32[](currentNodes);
// In the first iteration the nodes will be the leafs which are the local exit roots of each network
for (uint256 i = 0; i < currentNodes; i++) {
// The first rollup ID starts on 1
tmpTree[i] = rollupIDToRollupData[uint32(i + 1)].lastLocalExitRoot;
}
// This variable will keep track of the zero hashes
bytes32 currentZeroHashHeight = 0;
// This variable will keep track of the reamining levels to compute
uint256 remainingLevels = _EXIT_TREE_DEPTH;
// Calculate the root of the sub-tree that contains all the localExitRoots
while (currentNodes != 1) {
uint256 nextIterationNodes = currentNodes / 2 + (currentNodes % 2);
bytes32[] memory nextTmpTree = new bytes32[](nextIterationNodes);
for (uint256 i = 0; i < nextIterationNodes; i++) {
// if we are on the last iteration of the current level and the nodes are odd
if (i == nextIterationNodes - 1 && (currentNodes % 2) == 1) {
nextTmpTree[i] = keccak256(
abi.encodePacked(tmpTree[i * 2], currentZeroHashHeight)
);
} else {
nextTmpTree[i] = keccak256(
abi.encodePacked(tmpTree[i * 2], tmpTree[(i * 2) + 1])
);
}
}
// Update tree variables
tmpTree = nextTmpTree;
currentNodes = nextIterationNodes;
currentZeroHashHeight = keccak256(
abi.encodePacked(currentZeroHashHeight, currentZeroHashHeight)
);
remainingLevels--;
}
bytes32 currentRoot = tmpTree[0];
// Calculate remaining levels, since it's a sequencial merkle tree, the rest of the tree are zeroes
for (uint256 i = 0; i < remainingLevels; i++) {
currentRoot = keccak256(
abi.encodePacked(currentRoot, currentZeroHashHeight)
);
currentZeroHashHeight = keccak256(
abi.encodePacked(currentZeroHashHeight, currentZeroHashHeight)
);
}
return currentRoot;
}
/**
* @notice Get the last verified batch
*/
function getLastVerifiedBatch(
uint32 rollupID
) public view returns (uint64) {
return _getLastVerifiedBatch(rollupIDToRollupData[rollupID]);
}
/**
* @notice Get the last verified batch
*/
function _getLastVerifiedBatch(
RollupData storage rollup
) internal view returns (uint64) {
if (rollup.lastPendingState > 0) {
return
rollup
.pendingStateTransitions[rollup.lastPendingState]
.lastVerifiedBatch;
} else {
return rollup.lastVerifiedBatch;
}
}
/**
* @notice Returns a boolean that indicates if the pendingStateNum is or not consolidable
* @param rollupID Rollup id
* @param pendingStateNum Pending state number to check
* Note that his function does not check if the pending state currently exists, or if it's consolidated already
*/
function isPendingStateConsolidable(
uint32 rollupID,
uint64 pendingStateNum
) public view returns (bool) {
return
_isPendingStateConsolidable(
rollupIDToRollupData[rollupID],
pendingStateNum
);
}
/**
* @notice Returns a boolean that indicates if the pendingStateNum is or not consolidable
* @param rollup Rollup data storage pointer
* @param pendingStateNum Pending state number to check
* Note that his function does not check if the pending state currently exists, or if it's consolidated already
*/
function _isPendingStateConsolidable(
RollupData storage rollup,
uint64 pendingStateNum
) internal view returns (bool) {
return (rollup.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 = pol.balanceOf(address(this));
// Total Batches to be verified = total Sequenced Batches - total verified Batches
uint256 totalBatchesToVerify = totalSequencedBatches -
totalVerifiedBatches;
if (totalBatchesToVerify == 0) return 0;
return currentBalance / totalBatchesToVerify;
}
/**
* @notice Get batch fee
* This function is used instad of the automatic public view one,
* because in a future might change the behaviour and we will be able to mantain the interface
*/
function getBatchFee() public view returns (uint256) {
return _batchFee;
}
/**
* @notice Get forced batch fee
*/
function getForcedBatchFee() public view returns (uint256) {
return _batchFee * 100;
}
/**
* @notice Function to calculate the input snark bytes
* @param rollupID Rollup id used 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(
uint32 rollupID,
uint64 initNumBatch,
uint64 finalNewBatch,
bytes32 newLocalExitRoot,
bytes32 oldStateRoot,
bytes32 newStateRoot
) public view returns (bytes memory) {
return
_getInputSnarkBytes(
rollupIDToRollupData[rollupID],
initNumBatch,
finalNewBatch,
newLocalExitRoot,
oldStateRoot,
newStateRoot
);
}
/**
* @notice Function to calculate the input snark bytes
* @param rollup Rollup data storage pointer
* @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(
RollupData storage rollup,
uint64 initNumBatch,
uint64 finalNewBatch,
bytes32 newLocalExitRoot,
bytes32 oldStateRoot,
bytes32 newStateRoot
) internal view returns (bytes memory) {
// Sanity check
bytes32 oldAccInputHash = rollup
.sequencedBatches[initNumBatch]
.accInputHash;
bytes32 newAccInputHash = rollup
.sequencedBatches[finalNewBatch]
.accInputHash;
// Sanity check
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,
rollup.chainID,
rollup.forkID,
newStateRoot,
newAccInputHash,
newLocalExitRoot,
finalNewBatch
);
}
/**
* @notice Function to check if the state root is inside of the prime field
* @param newStateRoot New State root once the batch is processed
*/
function _checkStateRootInsidePrime(
uint256 newStateRoot
) internal 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;
}
}
/**
* @notice Get rollup state root given a batch number
* @param rollupID Rollup identifier
* @param batchNum Batch number
*/
function getRollupBatchNumToStateRoot(
uint32 rollupID,
uint64 batchNum
) public view returns (bytes32) {
return rollupIDToRollupData[rollupID].batchNumToStateRoot[batchNum];
}
/**
* @notice Get rollup sequence batches struct given a batch number
* @param rollupID Rollup identifier
* @param batchNum Batch number
*/
function getRollupSequencedBatches(
uint32 rollupID,
uint64 batchNum
) public view returns (SequencedBatchData memory) {
return rollupIDToRollupData[rollupID].sequencedBatches[batchNum];
}
/**
* @notice Get rollup sequence pending state struct given a batch number
* @param rollupID Rollup identifier
* @param batchNum Batch number
*/
function getRollupPendingStateTransitions(
uint32 rollupID,
uint64 batchNum
) public view returns (PendingState memory) {
return rollupIDToRollupData[rollupID].pendingStateTransitions[batchNum];
}
}
contracts/interfaces/IPolygonZkEVMBridge.sol
// 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;
}
contracts/v2/lib/PolygonAccessControlUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import "@openzeppelin/contracts-upgradeable/access/IAccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
/**
* @dev Contract AccessControlUpgradeable from Openzeppelin with the following modifications:
* - Delete ERC165Upgradeable dependencies, which is not important to our contract and save us the "gap"
* variables and let us have consistent storage
* - Add the legacy Owner variable, to be consistent with the previous one
* - Add custom errors
* - Replace _msgSender() with msg.sender
*/
abstract contract PolygonAccessControlUpgradeable is
Initializable,
ContextUpgradeable,
IAccessControlUpgradeable
{
function __AccessControl_init() internal onlyInitializing {}
// Legacy variable
/// @custom:oz-renamed-from _owner
address internal _legacyOwner;
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Thrown when the addres does not have the required role
*/
error AddressDoNotHaveRequiredRole();
/**
* @dev Thrown when the renounce address is not the message sender
*/
error AccessControlOnlyCanRenounceRolesForSelf();
/**
* @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 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 `msg.sender` 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, msg.sender);
}
/**
* @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 AddressDoNotHaveRequiredRole();
}
}
/**
* @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 {
if (account != msg.sender) {
revert AccessControlOnlyCanRenounceRolesForSelf();
}
_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, msg.sender);
}
}
/**
* @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, msg.sender);
}
}
/**
* @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[48] private __gap;
}
@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol
// 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");
}
}
}
contracts/v2/interfaces/IPolygonRollupManager.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
interface IPolygonRollupManager {
/**
* @dev Thrown when sender is not the PolygonZkEVM address
*/
error UpdateToSameRollupTypeID();
/**
* @dev Thrown when sender is not the PolygonZkEVM address
*/
error RollupMustExist();
/**
* @dev Thrown when sender is not the PolygonZkEVM address
*/
error SenderMustBeRollup();
/**
* @dev Thrown when sender is not the PolygonZkEVM address
*/
error TrustedAggregatorTimeoutNotExpired();
/**
* @dev Thrown when sender is not the PolygonZkEVM address
*/
error ExceedMaxVerifyBatches();
/**
* @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 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 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 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 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 the caller is not the pending admin
*/
error ChainIDAlreadyExist();
/**
* @dev Thrown when the caller is not the pending admin
*/
error MustSequenceSomeBatch();
/**
* @dev When a rollup type does not exist
*/
error RollupTypeDoesNotExist();
/**
* @dev When a rollup type does not exist
*/
error RollupTypeObsolete();
/**
* @dev When a rollup type does not exist
*/
error InitBatchMustMatchCurrentForkID();
/**
* @dev When a rollup type does not exist
*/
error UpdateNotCompatible();
/**
* @dev When a rollup type does not exist
*/
error BatchFeeOutOfRange();
/**
* @dev When a rollup type does not exist
*/
error AllzkEVMSequencedBatchesMustBeVerified();
/**
* @dev When adding an existing rollup where the rollup address already was added
*/
error RollupAddressAlreadyExist();
/**
* @dev When verifying proof for multiple roolups and they are not ordered by ID
*/
error RollupIDNotAscendingOrder();
/**
* @dev When try to create a new rollup and set a chainID bigger than 32 bits
*/
error ChainIDOutOfRange();
/**
* @dev When try to upgrade a rollup a sender that's not the admin of the rollup
*/
error OnlyRollupAdmin();
/**
* @dev When try to update a rollup with sequences pending to verify
*/
error AllSequencedMustBeVerified();
/**
* @dev Thrown when do not sequence any blob
*/
error MustSequenceSomeBlob();
/**
* @dev Thrown when the final verification sequence is below or equal the last verification sequence
*/
error FinalNumSequenceBelowLastVerifiedSequence();
/**
* @dev When the init sequence was verified in another forkID
*/
error InitSequenceMustMatchCurrentForkID();
/**
* @dev Thrown when the init num sequence does not match with the one in the pending state
*/
error InitSequenceNumDoesNotMatchPendingState();
/**
* @dev Thrown when the final num sequence does not match with the one in the pending state
*/
error FinalNumSequenceDoesNotMatchPendingState();
/**
* @dev Thrown when attempting to set a new multiplier zkgas in a invalid range of values
*/
error InvalidRangeMultiplierZkGasPrice();
/**
* @dev Thrown when attempting to set a seuqnece time target in an invalid range of values
*/
error InvalidRangeSequenceTimeTarget();
/**
* @dev When a set a zkgasprice out of range
*/
error zkGasPriceOfRange();
/**
* @dev Cannot update from network admin with unconsolidated pending state
*/
error CannotUpdateWithUnconsolidatedPendingState();
/**
* @dev Try to verify batches without any sequence data
*/
error EmptyVerifySequencesData();
/**
* @dev Update to old rollup ID
*/
error UpdateToOldRollupTypeID();
/**
* @dev All batches must be verified before the upgrade
*/
error AllBatchesMustBeVerified();
/**
* @dev Rollback batch is not sequenced
*/
error RollbackBatchIsNotValid();
/**
* @dev Rollback batch is not the end of any sequence
*/
error RollbackBatchIsNotEndOfSequence();
/**
* @dev rollbackBatches is called from a non authorized address
*/
error NotAllowedAddress();
}
@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol
// 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;
}
@openzeppelin/contracts5/proxy/transparent/TransparentUpgradeableProxy.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/TransparentUpgradeableProxy.sol)
pragma solidity ^0.8.20;
import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol";
import {ERC1967Proxy} from "../ERC1967/ERC1967Proxy.sol";
import {IERC1967} from "../../interfaces/IERC1967.sol";
import {ProxyAdmin} from "./ProxyAdmin.sol";
/**
* @dev Interface for {TransparentUpgradeableProxy}. In order to implement transparency, {TransparentUpgradeableProxy}
* does not implement this interface directly, and its upgradeability mechanism is implemented by an internal dispatch
* mechanism. The compiler is unaware that these functions are implemented by {TransparentUpgradeableProxy} and will not
* include them in the ABI so this interface must be used to interact with it.
*/
interface ITransparentUpgradeableProxy is IERC1967 {
function upgradeToAndCall(address, bytes calldata) external payable;
}
/**
* @dev This contract implements a proxy that is upgradeable through an associated {ProxyAdmin} instance.
*
* To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector
* clashing], which can potentially be used in an attack, this contract uses the
* https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two
* things that go hand in hand:
*
* 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if
* that call matches the {ITransparentUpgradeableProxy-upgradeToAndCall} function exposed by the proxy itself.
* 2. If the admin calls the proxy, it can call the `upgradeToAndCall` function but any other call won't be forwarded to
* the implementation. If the admin tries to call a function on the implementation it will fail with an error indicating
* the proxy admin cannot fallback to the target implementation.
*
* These properties mean that the admin account can only be used for upgrading the proxy, so it's best if it's a
* dedicated account that is not used for anything else. This will avoid headaches due to sudden errors when trying to
* call a function from the proxy implementation. For this reason, the proxy deploys an instance of {ProxyAdmin} and
* allows upgrades only if they come through it. You should think of the `ProxyAdmin` instance as the administrative
* interface of the proxy, including the ability to change who can trigger upgrades by transferring ownership.
*
* NOTE: The real interface of this proxy is that defined in `ITransparentUpgradeableProxy`. This contract does not
* inherit from that interface, and instead `upgradeToAndCall` is implicitly implemented using a custom dispatch
* mechanism in `_fallback`. Consequently, the compiler will not produce an ABI for this contract. This is necessary to
* fully implement transparency without decoding reverts caused by selector clashes between the proxy and the
* implementation.
*
* NOTE: This proxy does not inherit from {Context} deliberately. The {ProxyAdmin} of this contract won't send a
* meta-transaction in any way, and any other meta-transaction setup should be made in the implementation contract.
*
* IMPORTANT: This contract avoids unnecessary storage reads by setting the admin only during construction as an
* immutable variable, preventing any changes thereafter. However, the admin slot defined in ERC-1967 can still be
* overwritten by the implementation logic pointed to by this proxy. In such cases, the contract may end up in an
* undesirable state where the admin slot is different from the actual admin.
*
* WARNING: It is not recommended to extend this contract to add additional external functions. If you do so, the
* compiler will not check that there are no selector conflicts, due to the note above. A selector clash between any new
* function and the functions declared in {ITransparentUpgradeableProxy} will be resolved in favor of the new one. This
* could render the `upgradeToAndCall` function inaccessible, preventing upgradeability and compromising transparency.
*/
contract TransparentUpgradeableProxy is ERC1967Proxy {
// An immutable address for the admin to avoid unnecessary SLOADs before each call
// at the expense of removing the ability to change the admin once it's set.
// This is acceptable if the admin is always a ProxyAdmin instance or similar contract
// with its own ability to transfer the permissions to another account.
address private immutable _admin;
/**
* @dev The proxy caller is the current admin, and can't fallback to the proxy target.
*/
error ProxyDeniedAdminAccess();
/**
* @dev Initializes an upgradeable proxy managed by an instance of a {ProxyAdmin} with an `initialOwner`,
* backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in
* {ERC1967Proxy-constructor}.
*/
constructor(address _logic, address initialOwner, bytes memory _data) payable ERC1967Proxy(_logic, _data) {
_admin = address(new ProxyAdmin(initialOwner));
// Set the storage value and emit an event for ERC-1967 compatibility
ERC1967Utils.changeAdmin(_proxyAdmin());
}
/**
* @dev Returns the admin of this proxy.
*/
function _proxyAdmin() internal virtual returns (address) {
return _admin;
}
/**
* @dev If caller is the admin process the call internally, otherwise transparently fallback to the proxy behavior.
*/
function _fallback() internal virtual override {
if (msg.sender == _proxyAdmin()) {
if (msg.sig != ITransparentUpgradeableProxy.upgradeToAndCall.selector) {
revert ProxyDeniedAdminAccess();
} else {
_dispatchUpgradeToAndCall();
}
} else {
super._fallback();
}
}
/**
* @dev Upgrade the implementation of the proxy. See {ERC1967Utils-upgradeToAndCall}.
*
* Requirements:
*
* - If `data` is empty, `msg.value` must be zero.
*/
function _dispatchUpgradeToAndCall() private {
(address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes));
ERC1967Utils.upgradeToAndCall(newImplementation, data);
}
}
@openzeppelin/contracts5/utils/Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @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 or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* 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.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @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`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) 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 FailedInnerCall();
}
}
}
@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library MathUpgradeable {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10**64) {
value /= 10**64;
result += 64;
}
if (value >= 10**32) {
value /= 10**32;
result += 32;
}
if (value >= 10**16) {
value /= 10**16;
result += 16;
}
if (value >= 10**8) {
value /= 10**8;
result += 8;
}
if (value >= 10**4) {
value /= 10**4;
result += 4;
}
if (value >= 10**2) {
value /= 10**2;
result += 2;
}
if (value >= 10**1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);
}
}
}
@openzeppelin/contracts5/proxy/beacon/IBeacon.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.20;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {UpgradeableBeacon} will check that this address is a contract.
*/
function implementation() external view returns (address);
}
contracts/v2/interfaces/IPolygonRollupBase.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
interface IPolygonRollupBase {
function initialize(
address _admin,
address sequencer,
uint32 networkID,
address gasTokenAddress,
string memory sequencerURL,
string memory _networkName
) external;
function onVerifyBatches(
uint64 lastVerifiedBatch,
bytes32 newStateRoot,
address aggregator
) external;
function admin() external returns (address);
function rollbackBatches(
uint64 targetBatch,
bytes32 accInputHashToRollback
) external;
}
@openzeppelin/contracts5/interfaces/IERC1967.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol)
pragma solidity ^0.8.20;
/**
* @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
*/
interface IERC1967 {
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
}
@openzeppelin/contracts5/utils/Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
@openzeppelin/contracts5/access/Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.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.
*
* The initial owner is set to the address provided by the deployer. 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 Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @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 {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling 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 {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_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);
}
}
@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165Upgradeable.sol";
import "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165Upgradeable).interfaceId;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}
contracts/v2/lib/PolygonRollupBaseEtrog.sol
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import "../interfaces/IPolygonZkEVMGlobalExitRootV2.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "../../interfaces/IPolygonZkEVMErrors.sol";
import "../interfaces/IPolygonZkEVMVEtrogErrors.sol";
import "../PolygonRollupManager.sol";
import "../interfaces/IPolygonRollupBase.sol";
import "../interfaces/IPolygonZkEVMBridgeV2.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";
import "./PolygonConstantsBase.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.
*/
abstract contract PolygonRollupBaseEtrog is
Initializable,
PolygonConstantsBase,
IPolygonZkEVMVEtrogErrors,
IPolygonRollupBase
{
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 forcedGlobalExitRoot Global exit root, empty when sequencing a non forced batch
* @param forcedTimestamp Minimum timestamp of the force batch data, empty when sequencing a non forced batch
* @param forcedBlockHashL1 blockHash snapshot of the force batch data, empty when sequencing a non forced batch
*/
struct BatchData {
bytes transactions;
bytes32 forcedGlobalExitRoot;
uint64 forcedTimestamp;
bytes32 forcedBlockHashL1;
}
// 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;
// In order to encode the initialize transaction of the bridge there's have a constant part and the metadata which is variable
// Note the total transaction will be constrained to 65535 to avoid attacks and simplify the implementation
// List rlp: 1 listLenLen "0xf9" (0xf7 + 2), + listLen 2 (32 bytes + txData bytes) (do not accept more than 65535 bytes)
// First byte of the initialize bridge tx, indicates a list with a lengt of 2 bytes
// Since the minimum constant bytes will be: 259 (tx data empty) + 31 (tx parameters) = 259 (0x103) will always take 2 bytes to express the lenght of the rlp
// Note that more than 2 bytes of list len is not supported, since it's constrained to 65535
uint8 public constant INITIALIZE_TX_BRIDGE_LIST_LEN_LEN = 0xf9;
// Tx parameters until the bridge address
bytes public constant INITIALIZE_TX_BRIDGE_PARAMS = hex"80808401c9c38094";
// RLP encoded metadata (non empty)
// TxData bytes: 164 bytes data ( signature 4 bytes + 5 parameters*32bytes +
// (abi encoded metadata: 32 bytes position + 32 bytes len + 32 bytes position name + 32 bytes length name + 32 bytes position Symbol + 32 bytes length Symbol
//+ 32 bytes decimal )) min 7*32 bytes =
// = 164 bytes + 224 bytes = 388 (0x0184) minimum
// Extra data: nameLen padded to 32 bytes + symbol len padded to 32 bytes
// Constant bytes: 1 nonce "0x80" + 1 gasPrice "0x80" + 5 gasLimit "0x8401c9c380" (30M gas)
// + 21 to ("0x94" + bridgeAddress") + 1 value "0x80" + 1 stringLenLen "0xb9" (0xb7 + 2) +
// stringLen (0x0184 + nameLen padded to 32 bytes + symbol len padded to 32 bytes) + txData bytes = 32 bytes + txData bytes
uint16 public constant INITIALIZE_TX_CONSTANT_BYTES = 32;
// Tx parameters after the bridge address
bytes public constant INITIALIZE_TX_BRIDGE_PARAMS_AFTER_BRIDGE_ADDRESS =
hex"80b9";
// RLP empty metadata
// TxData empty metadata bytes: 164 bytes data ( signature 4 bytes + 5 parameters*32bytes +
// (abi encoded metadata: 32 bytes position + 32 bytes len = 2*32 bytes =
// = 164 bytes + 64 bytes = 228 (0xe4)
// Constant bytes empty metadata : 1 nonce "0x80" + 1 gasPrice "0x80" + 5 gasLimit "0x8401c9c380" (30M gas)
// + 21 to ("0x94" + bridgeAddress") + 1 value "0x80" + 1 stringLenLen "0xb8" (0xb7 + 1) +
// 1 stringLen (0xe4) + txData bytes = 31 bytes + txData bytes empty metadata 228 = 259
uint16 public constant INITIALIZE_TX_CONSTANT_BYTES_EMPTY_METADATA = 31;
uint8 public constant INITIALIZE_TX_DATA_LEN_EMPTY_METADATA = 228; // 0xe4
// Tx parameters after the bridge address
bytes
public constant INITIALIZE_TX_BRIDGE_PARAMS_AFTER_BRIDGE_ADDRESS_EMPTY_METADATA =
hex"80b8";
// Signature used to initialize the bridge
// V parameter of the initialize signature
uint8 public constant SIGNATURE_INITIALIZE_TX_V = 27;
// R parameter of the initialize signature
bytes32 public constant SIGNATURE_INITIALIZE_TX_R =
0x00000000000000000000000000000000000000000000000000000005ca1ab1e0;
// S parameter of the initialize signature
bytes32 public constant SIGNATURE_INITIALIZE_TX_S =
0x000000000000000000000000000000000000000000000000000000005ca1ab1e;
// Effective percentage of the initalize transaction
bytes1 public constant INITIALIZE_TX_EFFECTIVE_PERCENTAGE = 0xFF;
// Global Exit Root address L2
IBasePolygonZkEVMGlobalExitRoot
public constant GLOBAL_EXIT_ROOT_MANAGER_L2 =
IBasePolygonZkEVMGlobalExitRoot(
0xa40D5f56745a118D0906a34E69aeC8C0Db1cB8fA
);
// Timestamp range that's given to the sequencer as a safety measure to avoid reverts if the transaction is mined to quickly
uint256 public constant TIMESTAMP_RANGE = 36;
// POL token address
IERC20Upgradeable public immutable pol;
// Global Exit Root interface
IPolygonZkEVMGlobalExitRootV2 public immutable globalExitRootManager;
// PolygonZkEVM Bridge Address
IPolygonZkEVMBridgeV2 public immutable bridgeAddress;
// Rollup manager
PolygonRollupManager public immutable rollupManager;
// Address that will be able to adjust contract parameters
address public admin;
// This account will be able to accept the admin role
address public pendingAdmin;
// Trusted sequencer address
address public trustedSequencer;
// Trusted sequencer URL
string public trustedSequencerURL;
// L2 network name
string public networkName;
// Current accumulate input hash
bytes32 public lastAccInputHash;
// 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 forcedGlobalExitRoot, unint64 forcedTimestamp, bytes32 forcedBlockHashL1)
mapping(uint64 => bytes32) public forcedBatches;
// Last forced batch
uint64 public lastForceBatch;
// Last forced batch included in the sequence
uint64 public lastForceBatchSequenced;
// Force batch timeout
uint64 public forceBatchTimeout;
// Indicates what address is able to do forced batches
// If the address is set to 0, forced batches are open to everyone
address public forceBatchAddress;
// Token address that will be used to pay gas fees in this rollup. This variable it's just for read purposes
address public gasTokenAddress;
// Native network of the token address of the gas tokena address. This variable it's just for read purposes
uint32 public gasTokenNetwork;
/**
* @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[50] private _gap;
/**
* @dev Emitted when the trusted sequencer sends a new batch of transactions
*/
event SequenceBatches(uint64 indexed numBatch, bytes32 l1InfoRoot);
/**
* @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 the contract is initialized, contain the first sequenced transaction
*/
event InitialSequenceBatches(
bytes transactions,
bytes32 lastGlobalExitRoot,
address sequencer
);
/**
* @dev Emitted when a aggregator verifies batches
*/
event VerifyBatches(
uint64 indexed numBatch,
bytes32 stateRoot,
address indexed aggregator
);
/**
* @dev Emitted when a aggregator verifies batches
*/
event RollbackBatches(
uint64 indexed targetBatch,
bytes32 accInputHashToRollback
);
/**
* @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 update the force batch timeout
*/
event SetForceBatchTimeout(uint64 newforceBatchTimeout);
/**
* @dev Emitted when the admin update the force batch address
*/
event SetForceBatchAddress(address newForceBatchAddress);
/**
* @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);
// General parameters that will have in common all networks that deploys rollup manager
/**
* @param _globalExitRootManager Global exit root manager address
* @param _pol POL token address
* @param _bridgeAddress Bridge address
* @param _rollupManager Global exit root manager address
*/
constructor(
IPolygonZkEVMGlobalExitRootV2 _globalExitRootManager,
IERC20Upgradeable _pol,
IPolygonZkEVMBridgeV2 _bridgeAddress,
PolygonRollupManager _rollupManager
) {
globalExitRootManager = _globalExitRootManager;
pol = _pol;
bridgeAddress = _bridgeAddress;
rollupManager = _rollupManager;
}
/**
* @param _admin Admin address
* @param sequencer Trusted sequencer address
* @param networkID Indicates the network identifier that will be used in the bridge
* @param _gasTokenAddress Indicates the token address in mainnet that will be used as a gas token
* Note if a wrapped token of the bridge is used, the original network and address of this wrapped are used instead
* @param sequencerURL Trusted sequencer URL
* @param _networkName L2 network name
*/
function initialize(
address _admin,
address sequencer,
uint32 networkID,
address _gasTokenAddress,
string memory sequencerURL,
string memory _networkName
) external virtual onlyRollupManager initializer {
bytes memory gasTokenMetadata = _verifyOrigin(_gasTokenAddress);
// Sequence transaction to initilize the bridge
// Calculate transaction to initialize the bridge
bytes memory transaction = generateInitializeTransaction(
networkID,
gasTokenAddress,
gasTokenNetwork,
gasTokenMetadata
);
bytes32 currentTransactionsHash = keccak256(transaction);
// Get current timestamp and global exit root
uint64 currentTimestamp = uint64(block.timestamp);
bytes32 lastGlobalExitRoot = globalExitRootManager
.getLastGlobalExitRoot();
// Add the transaction to the sequence as if it was a force transaction
bytes32 newAccInputHash = keccak256(
abi.encodePacked(
bytes32(0), // Current acc Input hash
currentTransactionsHash,
lastGlobalExitRoot, // Global exit root
currentTimestamp,
sequencer,
blockhash(block.number - 1)
)
);
lastAccInputHash = newAccInputHash;
rollupManager.onSequenceBatches(
uint64(1), // num total batches
newAccInputHash
);
// Set initialize variables
admin = _admin;
trustedSequencer = sequencer;
trustedSequencerURL = sequencerURL;
networkName = _networkName;
forceBatchAddress = _admin;
// Constant deployment variables
forceBatchTimeout = 5 days;
emit InitialSequenceBatches(transaction, lastGlobalExitRoot, sequencer);
}
modifier onlyAdmin() {
if (admin != msg.sender) {
revert OnlyAdmin();
}
_;
}
modifier onlyTrustedSequencer() {
if (trustedSequencer != msg.sender) {
revert OnlyTrustedSequencer();
}
_;
}
modifier isSenderAllowedToForceBatches() {
address cacheForceBatchAddress = forceBatchAddress;
if (
cacheForceBatchAddress != address(0) &&
cacheForceBatchAddress != msg.sender
) {
revert ForceBatchNotAllowed();
}
_;
}
modifier onlyRollupManager() {
if (address(rollupManager) != msg.sender) {
revert OnlyRollupManager();
}
_;
}
/////////////////////////////////////
// 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 l1InfoTreeLeafCount Index of the L1InfoRoot that will be used in this sequence
* @param maxSequenceTimestamp Max timestamp of the sequence. This timestamp must be inside a safety range (actual + 36 seconds).
* This timestamp should be equal or higher of the last block inside the sequence, otherwise this batch will be invalidated by circuit.
* @param expectedFinalAccInputHash This parameter must match the acc input hash after hash all the batch data
* This will be a protection for the sequencer to avoid sending undesired data
* @param l2Coinbase Address that will receive the fees from L2
* note Pol is not a reentrant token
*/
function sequenceBatches(
BatchData[] calldata batches,
uint32 l1InfoTreeLeafCount,
uint64 maxSequenceTimestamp,
bytes32 expectedFinalAccInputHash,
address l2Coinbase
) public virtual onlyTrustedSequencer {
uint256 batchesNum = batches.length;
if (batchesNum == 0) {
revert SequenceZeroBatches();
}
if (batchesNum > _MAX_VERIFY_BATCHES) {
revert ExceedMaxVerifyBatches();
}
// Check max sequence timestamp inside of range
if (
uint256(maxSequenceTimestamp) > (block.timestamp + TIMESTAMP_RANGE)
) {
revert MaxTimestampSequenceInvalid();
}
// Update global exit root if there are new deposits
bridgeAddress.updateGlobalExitRoot();
// Get global batch variables
bytes32 l1InfoRoot = globalExitRootManager.l1InfoRootMap(
l1InfoTreeLeafCount
);
if (l1InfoRoot == bytes32(0)) {
revert L1InfoTreeLeafCountInvalid();
}
// Store storage variables in memory, to save gas, because will be overrided multiple times
uint64 currentLastForceBatchSequenced = lastForceBatchSequenced;
bytes32 currentAccInputHash = lastAccInputHash;
// 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.forcedTimestamp > 0) {
currentLastForceBatchSequenced++;
// Check forced data matches
bytes32 hashedForcedBatchData = keccak256(
abi.encodePacked(
currentTransactionsHash,
currentBatch.forcedGlobalExitRoot,
currentBatch.forcedTimestamp,
currentBatch.forcedBlockHashL1
)
);
if (
hashedForcedBatchData !=
forcedBatches[currentLastForceBatchSequenced]
) {
revert ForcedDataDoesNotMatch();
}
// Calculate next accumulated input hash
currentAccInputHash = keccak256(
abi.encodePacked(
currentAccInputHash,
currentTransactionsHash,
currentBatch.forcedGlobalExitRoot,
currentBatch.forcedTimestamp,
l2Coinbase,
currentBatch.forcedBlockHashL1
)
);
// Delete forceBatch data since won't be used anymore
delete forcedBatches[currentLastForceBatchSequenced];
} else {
// Note that forcedGlobalExitRoot and forcedBlockHashL1 remain unused and unchecked in this path
// The synchronizer should be aware of that
if (
currentBatch.transactions.length >
_MAX_TRANSACTIONS_BYTE_LENGTH
) {
revert TransactionsLengthAboveMax();
}
// Calculate next accumulated input hash
currentAccInputHash = keccak256(
abi.encodePacked(
currentAccInputHash,
currentTransactionsHash,
l1InfoRoot,
maxSequenceTimestamp,
l2Coinbase,
bytes32(0)
)
);
}
}
// Sanity check, should be unreachable
if (currentLastForceBatchSequenced > lastForceBatch) {
revert ForceBatchesOverflow();
}
// Store back the storage variables
lastAccInputHash = currentAccInputHash;
uint256 nonForcedBatchesSequenced = batchesNum;
// Check if there has been forced batches
if (currentLastForceBatchSequenced != initLastForceBatchSequenced) {
uint64 forcedBatchesSequenced = currentLastForceBatchSequenced -
initLastForceBatchSequenced;
// substract forced batches
nonForcedBatchesSequenced -= forcedBatchesSequenced;
// Transfer pol for every forced batch submitted
pol.safeTransfer(
address(rollupManager),
calculatePolPerForceBatch() * (forcedBatchesSequenced)
);
// Store new last force batch sequenced
lastForceBatchSequenced = currentLastForceBatchSequenced;
}
// Pay collateral for every non-forced batch submitted
pol.safeTransferFrom(
msg.sender,
address(rollupManager),
rollupManager.getBatchFee() * nonForcedBatchesSequenced
);
uint64 currentBatchSequenced = rollupManager.onSequenceBatches(
uint64(batchesNum),
currentAccInputHash
);
// Check expectedFinalAccInputHash
if (currentAccInputHash != expectedFinalAccInputHash) {
revert FinalAccInputHashDoesNotMatch();
}
emit SequenceBatches(currentBatchSequenced, l1InfoRoot);
}
/**
* @notice Callback on verify batches, can only be called by the rollup manager
* @param lastVerifiedBatch Last verified batch
* @param newStateRoot new state root
* @param aggregator Aggregator address
*/
function onVerifyBatches(
uint64 lastVerifiedBatch,
bytes32 newStateRoot,
address aggregator
) public virtual override onlyRollupManager {
emit VerifyBatches(lastVerifiedBatch, newStateRoot, aggregator);
}
/**
* @notice Callback on rollback batches, can only be called by the rollup manager
* @param targetBatch Batch to rollback up to but not including this batch
* @param accInputHashToRollback Acc input hash to rollback
*/
function rollbackBatches(
uint64 targetBatch,
bytes32 accInputHashToRollback
) public virtual override onlyRollupManager {
// Rollback the accumulated input hash
lastAccInputHash = accInputHashToRollback;
emit RollbackBatches(targetBatch, accInputHashToRollback);
}
////////////////////////////
// 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 polAmount Max amount of pol tokens that the sender is willing to pay
*/
function forceBatch(
bytes calldata transactions,
uint256 polAmount
) public virtual isSenderAllowedToForceBatches {
// Check if rollup manager is on emergency state
if (rollupManager.isEmergencyState()) {
revert ForceBatchesNotAllowedOnEmergencyState();
}
// Calculate pol collateral
uint256 polFee = rollupManager.getForcedBatchFee();
if (polFee > polAmount) {
revert NotEnoughPOLAmount();
}
if (transactions.length > _MAX_FORCE_BATCH_BYTE_LENGTH) {
revert TransactionsLengthAboveMax();
}
// keep the pol fees on this contract until forced it's sequenced
pol.safeTransferFrom(msg.sender, address(this), polFee);
// Get globalExitRoot global exit root
bytes32 lastGlobalExitRoot = globalExitRootManager
.getLastGlobalExitRoot();
// Update forcedBatches mapping
lastForceBatch++;
forcedBatches[lastForceBatch] = keccak256(
abi.encodePacked(
keccak256(transactions),
lastGlobalExitRoot,
uint64(block.timestamp),
blockhash(block.number - 1)
)
);
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(
BatchData[] calldata batches
) external virtual isSenderAllowedToForceBatches {
// Check if rollup manager is on emergency state
if (
rollupManager.lastDeactivatedEmergencyStateTimestamp() +
_HALT_AGGREGATION_TIMEOUT >
block.timestamp
) {
revert HaltTimeoutNotExpiredAfterEmergencyState();
}
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 currentLastForceBatchSequenced = lastForceBatchSequenced;
bytes32 currentAccInputHash = lastAccInputHash;
// Sequence force batches
for (uint256 i = 0; i < batchesNum; i++) {
// Load current sequence
BatchData 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.forcedGlobalExitRoot,
currentBatch.forcedTimestamp,
currentBatch.forcedBlockHashL1
)
);
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.forcedTimestamp + forceBatchTimeout >
block.timestamp
) {
revert ForceBatchTimeoutNotExpired();
}
}
// Calculate next acc input hash
currentAccInputHash = keccak256(
abi.encodePacked(
currentAccInputHash,
currentTransactionsHash,
currentBatch.forcedGlobalExitRoot,
currentBatch.forcedTimestamp,
msg.sender,
currentBatch.forcedBlockHashL1
)
);
}
// Transfer pol for every forced batch submitted
pol.safeTransfer(
address(rollupManager),
calculatePolPerForceBatch() * (batchesNum)
);
// Store back the storage variables
lastAccInputHash = currentAccInputHash;
lastForceBatchSequenced = currentLastForceBatchSequenced;
uint64 currentBatchSequenced = rollupManager.onSequenceBatches(
uint64(batchesNum),
currentAccInputHash
);
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 change the force batch address, that will be allowed to force batches
* If address 0 is set, then everyone is able to force batches, this action is irreversible
* @param newForceBatchAddress New force batch address
*/
function setForceBatchAddress(
address newForceBatchAddress
) external onlyAdmin {
if (forceBatchAddress == address(0)) {
revert ForceBatchesDecentralized();
}
forceBatchAddress = newForceBatchAddress;
emit SetForceBatchAddress(newForceBatchAddress);
}
/**
* @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 (!rollupManager.isEmergencyState()) {
if (newforceBatchTimeout >= forceBatchTimeout) {
revert InvalidRangeForceBatchTimeout();
}
}
forceBatchTimeout = newforceBatchTimeout;
emit SetForceBatchTimeout(newforceBatchTimeout);
}
/**
* @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);
}
//////////////////
// view/pure functions
//////////////////
/**
* @notice Function to calculate the reward for a forced batch
*/
function calculatePolPerForceBatch() public view returns (uint256) {
uint256 currentBalance = pol.balanceOf(address(this));
// Pending forced Batches = last forced batch added - last forced batch sequenced
uint256 pendingForcedBatches = lastForceBatch - lastForceBatchSequenced;
if (pendingForcedBatches == 0) return 0;
return currentBalance / pendingForcedBatches;
}
/**
* @notice Generate Initialize transaction for hte bridge on L2
* @param networkID Indicates the network identifier that will be used in the bridge
* @param _gasTokenAddress Indicates the token address that will be used to pay gas fees in the new rollup
* @param _gasTokenNetwork Indicates the native network of the token address
* @param _gasTokenMetadata Abi encoded gas token metadata
*/
function generateInitializeTransaction(
uint32 networkID,
address _gasTokenAddress,
uint32 _gasTokenNetwork,
bytes memory _gasTokenMetadata
) public view returns (bytes memory) {
bytes memory initializeBrigeData = abi.encodeCall(
IPolygonZkEVMBridgeV2.initialize,
(
networkID,
_gasTokenAddress,
_gasTokenNetwork,
GLOBAL_EXIT_ROOT_MANAGER_L2,
address(0), // Rollup manager on L2 does not exist
_gasTokenMetadata
)
);
bytes memory bytesToSign;
if (_gasTokenMetadata.length == 0) {
bytesToSign = abi.encodePacked(
INITIALIZE_TX_BRIDGE_LIST_LEN_LEN,
uint16(initializeBrigeData.length) +
INITIALIZE_TX_CONSTANT_BYTES_EMPTY_METADATA, // do not support more than 2 bytes of length, intended to revert on overflow
INITIALIZE_TX_BRIDGE_PARAMS,
bridgeAddress,
INITIALIZE_TX_BRIDGE_PARAMS_AFTER_BRIDGE_ADDRESS_EMPTY_METADATA,
INITIALIZE_TX_DATA_LEN_EMPTY_METADATA,
initializeBrigeData
);
} else {
// Do not support more than 65535 bytes
if (initializeBrigeData.length > type(uint16).max) {
revert HugeTokenMetadataNotSupported();
}
uint16 initializeBrigeDataLen = uint16(initializeBrigeData.length);
bytesToSign = abi.encodePacked(
INITIALIZE_TX_BRIDGE_LIST_LEN_LEN,
uint16(initializeBrigeData.length) +
INITIALIZE_TX_CONSTANT_BYTES, // do not support more than 2 bytes of length, intended to revert on overflow
INITIALIZE_TX_BRIDGE_PARAMS,
bridgeAddress,
INITIALIZE_TX_BRIDGE_PARAMS_AFTER_BRIDGE_ADDRESS,
initializeBrigeDataLen,
initializeBrigeData
);
}
// Sanity check that the ecrecover will work
// Should never happen that giving a valid signature, ecrecover "breaks"
address signer = ecrecover(
keccak256(bytesToSign),
SIGNATURE_INITIALIZE_TX_V,
SIGNATURE_INITIALIZE_TX_R,
SIGNATURE_INITIALIZE_TX_S
);
if (signer == address(0)) {
revert InvalidInitializeTransaction();
}
bytes memory transaction = abi.encodePacked(
bytesToSign,
SIGNATURE_INITIALIZE_TX_R,
SIGNATURE_INITIALIZE_TX_S,
SIGNATURE_INITIALIZE_TX_V,
INITIALIZE_TX_EFFECTIVE_PERCENTAGE
);
return transaction;
}
function _verifyOrigin(
address _gasTokenAddress
) internal virtual returns (bytes memory gasTokenMetadata) {
if (_gasTokenAddress != address(0)) {
// Ask for token metadata, the same way is enconded in the bridge
// Note that this function will revert if the token is not in this network
// Note that this could be a possible reentrant call, but cannot make changes on the state since are static call
gasTokenMetadata = bridgeAddress.getTokenMetadata(_gasTokenAddress);
// Check gas token address on the bridge
(
uint32 originWrappedNetwork,
address originWrappedAddress
) = bridgeAddress.wrappedTokenToTokenInfo(_gasTokenAddress);
if (originWrappedNetwork != 0) {
// It's a wrapped token, get the wrapped parameters
gasTokenAddress = originWrappedAddress;
gasTokenNetwork = originWrappedNetwork;
} else {
// gasTokenNetwork will be mainnet, for instance 0
gasTokenAddress = _gasTokenAddress;
}
}
}
}
@openzeppelin/contracts5/proxy/ERC1967/ERC1967Proxy.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Proxy.sol)
pragma solidity ^0.8.20;
import {Proxy} from "../Proxy.sol";
import {ERC1967Utils} from "./ERC1967Utils.sol";
/**
* @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
* implementation address that can be changed. This address is stored in storage in the location specified by
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
* implementation behind the proxy.
*/
contract ERC1967Proxy is Proxy {
/**
* @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation`.
*
* If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an
* encoded function call, and allows initializing the storage of the proxy like a Solidity constructor.
*
* Requirements:
*
* - If `data` is empty, `msg.value` must be zero.
*/
constructor(address implementation, bytes memory _data) payable {
ERC1967Utils.upgradeToAndCall(implementation, _data);
}
/**
* @dev Returns the current implementation address.
*
* TIP: To get this value clients can read directly from the storage slot shown below (specified by EIP1967) using
* the https://eth.wiki/json-rpc/API#eth_getstorageat[`eth_getStorageAt`] RPC call.
* `0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc`
*/
function _implementation() internal view virtual override returns (address) {
return ERC1967Utils.getImplementation();
}
}
Compiler Settings
{"viaIR":true,"outputSelection":{"*":{"*":["*"],"":["*"]}},"optimizer":{"runs":200,"enabled":true},"libraries":{},"evmVersion":"paris"}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_globalExitRootManager","internalType":"contract IPolygonZkEVMGlobalExitRootV2"},{"type":"address","name":"_pol","internalType":"contract IERC20Upgradeable"},{"type":"address","name":"_bridgeAddress","internalType":"contract IPolygonZkEVMBridge"}]},{"type":"error","name":"AccessControlOnlyCanRenounceRolesForSelf","inputs":[]},{"type":"error","name":"AddressDoNotHaveRequiredRole","inputs":[]},{"type":"error","name":"AllBatchesMustBeVerified","inputs":[]},{"type":"error","name":"AllSequencedMustBeVerified","inputs":[]},{"type":"error","name":"AllzkEVMSequencedBatchesMustBeVerified","inputs":[]},{"type":"error","name":"BatchFeeOutOfRange","inputs":[]},{"type":"error","name":"CannotUpdateWithUnconsolidatedPendingState","inputs":[]},{"type":"error","name":"ChainIDAlreadyExist","inputs":[]},{"type":"error","name":"ChainIDOutOfRange","inputs":[]},{"type":"error","name":"EmptyVerifySequencesData","inputs":[]},{"type":"error","name":"ExceedMaxVerifyBatches","inputs":[]},{"type":"error","name":"FinalNumBatchBelowLastVerifiedBatch","inputs":[]},{"type":"error","name":"FinalNumBatchDoesNotMatchPendingState","inputs":[]},{"type":"error","name":"FinalNumSequenceBelowLastVerifiedSequence","inputs":[]},{"type":"error","name":"FinalNumSequenceDoesNotMatchPendingState","inputs":[]},{"type":"error","name":"FinalPendingStateNumInvalid","inputs":[]},{"type":"error","name":"HaltTimeoutNotExpired","inputs":[]},{"type":"error","name":"InitBatchMustMatchCurrentForkID","inputs":[]},{"type":"error","name":"InitNumBatchAboveLastVerifiedBatch","inputs":[]},{"type":"error","name":"InitNumBatchDoesNotMatchPendingState","inputs":[]},{"type":"error","name":"InitSequenceMustMatchCurrentForkID","inputs":[]},{"type":"error","name":"InitSequenceNumDoesNotMatchPendingState","inputs":[]},{"type":"error","name":"InvalidProof","inputs":[]},{"type":"error","name":"InvalidRangeBatchTimeTarget","inputs":[]},{"type":"error","name":"InvalidRangeMultiplierBatchFee","inputs":[]},{"type":"error","name":"InvalidRangeMultiplierZkGasPrice","inputs":[]},{"type":"error","name":"InvalidRangeSequenceTimeTarget","inputs":[]},{"type":"error","name":"MustSequenceSomeBatch","inputs":[]},{"type":"error","name":"MustSequenceSomeBlob","inputs":[]},{"type":"error","name":"NewAccInputHashDoesNotExist","inputs":[]},{"type":"error","name":"NewPendingStateTimeoutMustBeLower","inputs":[]},{"type":"error","name":"NewStateRootNotInsidePrime","inputs":[]},{"type":"error","name":"NewTrustedAggregatorTimeoutMustBeLower","inputs":[]},{"type":"error","name":"NotAllowedAddress","inputs":[]},{"type":"error","name":"OldAccInputHashDoesNotExist","inputs":[]},{"type":"error","name":"OldStateRootDoesNotExist","inputs":[]},{"type":"error","name":"OnlyEmergencyState","inputs":[]},{"type":"error","name":"OnlyNotEmergencyState","inputs":[]},{"type":"error","name":"OnlyRollupAdmin","inputs":[]},{"type":"error","name":"PendingStateDoesNotExist","inputs":[]},{"type":"error","name":"PendingStateInvalid","inputs":[]},{"type":"error","name":"PendingStateNotConsolidable","inputs":[]},{"type":"error","name":"RollbackBatchIsNotEndOfSequence","inputs":[]},{"type":"error","name":"RollbackBatchIsNotValid","inputs":[]},{"type":"error","name":"RollupAddressAlreadyExist","inputs":[]},{"type":"error","name":"RollupIDNotAscendingOrder","inputs":[]},{"type":"error","name":"RollupMustExist","inputs":[]},{"type":"error","name":"RollupTypeDoesNotExist","inputs":[]},{"type":"error","name":"RollupTypeObsolete","inputs":[]},{"type":"error","name":"SenderMustBeRollup","inputs":[]},{"type":"error","name":"StoredRootMustBeDifferentThanNewRoot","inputs":[]},{"type":"error","name":"TrustedAggregatorTimeoutNotExpired","inputs":[]},{"type":"error","name":"UpdateNotCompatible","inputs":[]},{"type":"error","name":"UpdateToOldRollupTypeID","inputs":[]},{"type":"error","name":"UpdateToSameRollupTypeID","inputs":[]},{"type":"error","name":"zkGasPriceOfRange","inputs":[]},{"type":"event","name":"AddExistingRollup","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32","indexed":true},{"type":"uint64","name":"forkID","internalType":"uint64","indexed":false},{"type":"address","name":"rollupAddress","internalType":"address","indexed":false},{"type":"uint64","name":"chainID","internalType":"uint64","indexed":false},{"type":"uint8","name":"rollupCompatibilityID","internalType":"uint8","indexed":false},{"type":"uint64","name":"lastVerifiedBatchBeforeUpgrade","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"event","name":"AddNewRollupType","inputs":[{"type":"uint32","name":"rollupTypeID","internalType":"uint32","indexed":true},{"type":"address","name":"consensusImplementation","internalType":"address","indexed":false},{"type":"address","name":"verifier","internalType":"address","indexed":false},{"type":"uint64","name":"forkID","internalType":"uint64","indexed":false},{"type":"uint8","name":"rollupCompatibilityID","internalType":"uint8","indexed":false},{"type":"bytes32","name":"genesis","internalType":"bytes32","indexed":false},{"type":"string","name":"description","internalType":"string","indexed":false}],"anonymous":false},{"type":"event","name":"ConsolidatePendingState","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32","indexed":true},{"type":"uint64","name":"numBatch","internalType":"uint64","indexed":false},{"type":"bytes32","name":"stateRoot","internalType":"bytes32","indexed":false},{"type":"bytes32","name":"exitRoot","internalType":"bytes32","indexed":false},{"type":"uint64","name":"pendingStateNum","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"event","name":"CreateNewRollup","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32","indexed":true},{"type":"uint32","name":"rollupTypeID","internalType":"uint32","indexed":false},{"type":"address","name":"rollupAddress","internalType":"address","indexed":false},{"type":"uint64","name":"chainID","internalType":"uint64","indexed":false},{"type":"address","name":"gasTokenAddress","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"EmergencyStateActivated","inputs":[],"anonymous":false},{"type":"event","name":"EmergencyStateDeactivated","inputs":[],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"type":"uint8","name":"version","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"ObsoleteRollupType","inputs":[{"type":"uint32","name":"rollupTypeID","internalType":"uint32","indexed":true}],"anonymous":false},{"type":"event","name":"OnSequenceBatches","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32","indexed":true},{"type":"uint64","name":"lastBatchSequenced","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"event","name":"OverridePendingState","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32","indexed":true},{"type":"uint64","name":"numBatch","internalType":"uint64","indexed":false},{"type":"bytes32","name":"stateRoot","internalType":"bytes32","indexed":false},{"type":"bytes32","name":"exitRoot","internalType":"bytes32","indexed":false},{"type":"address","name":"aggregator","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"ProveNonDeterministicPendingState","inputs":[{"type":"bytes32","name":"storedStateRoot","internalType":"bytes32","indexed":false},{"type":"bytes32","name":"provedStateRoot","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"RoleAdminChanged","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"bytes32","name":"previousAdminRole","internalType":"bytes32","indexed":true},{"type":"bytes32","name":"newAdminRole","internalType":"bytes32","indexed":true}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RollbackBatches","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32","indexed":true},{"type":"uint64","name":"targetBatch","internalType":"uint64","indexed":true},{"type":"bytes32","name":"accInputHashToRollback","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"SetBatchFee","inputs":[{"type":"uint256","name":"newBatchFee","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetMultiplierBatchFee","inputs":[{"type":"uint16","name":"newMultiplierBatchFee","internalType":"uint16","indexed":false}],"anonymous":false},{"type":"event","name":"SetPendingStateTimeout","inputs":[{"type":"uint64","name":"newPendingStateTimeout","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"event","name":"SetTrustedAggregator","inputs":[{"type":"address","name":"newTrustedAggregator","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"SetTrustedAggregatorTimeout","inputs":[{"type":"uint64","name":"newTrustedAggregatorTimeout","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"event","name":"SetVerifyBatchTimeTarget","inputs":[{"type":"uint64","name":"newVerifyBatchTimeTarget","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"event","name":"UpdateRollup","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32","indexed":true},{"type":"uint32","name":"newRollupTypeID","internalType":"uint32","indexed":false},{"type":"uint64","name":"lastVerifiedBatchBeforeUpgrade","internalType":"uint64","indexed":false}],"anonymous":false},{"type":"event","name":"VerifyBatches","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32","indexed":true},{"type":"uint64","name":"numBatch","internalType":"uint64","indexed":false},{"type":"bytes32","name":"stateRoot","internalType":"bytes32","indexed":false},{"type":"bytes32","name":"exitRoot","internalType":"bytes32","indexed":false},{"type":"address","name":"aggregator","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"VerifyBatchesTrustedAggregator","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32","indexed":true},{"type":"uint64","name":"numBatch","internalType":"uint64","indexed":false},{"type":"bytes32","name":"stateRoot","internalType":"bytes32","indexed":false},{"type":"bytes32","name":"exitRoot","internalType":"bytes32","indexed":false},{"type":"address","name":"aggregator","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"DEFAULT_ADMIN_ROLE","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"activateEmergencyState","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addExistingRollup","inputs":[{"type":"address","name":"rollupAddress","internalType":"contract IPolygonRollupBase"},{"type":"address","name":"verifier","internalType":"contract IVerifierRollup"},{"type":"uint64","name":"forkID","internalType":"uint64"},{"type":"uint64","name":"chainID","internalType":"uint64"},{"type":"bytes32","name":"genesis","internalType":"bytes32"},{"type":"uint8","name":"rollupCompatibilityID","internalType":"uint8"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addNewRollupType","inputs":[{"type":"address","name":"consensusImplementation","internalType":"address"},{"type":"address","name":"verifier","internalType":"contract IVerifierRollup"},{"type":"uint64","name":"forkID","internalType":"uint64"},{"type":"uint8","name":"rollupCompatibilityID","internalType":"uint8"},{"type":"bytes32","name":"genesis","internalType":"bytes32"},{"type":"string","name":"description","internalType":"string"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IPolygonZkEVMBridge"}],"name":"bridgeAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"calculateRewardPerBatch","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"rollupID","internalType":"uint32"}],"name":"chainIDToRollupID","inputs":[{"type":"uint64","name":"chainID","internalType":"uint64"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"consolidatePendingState","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32"},{"type":"uint64","name":"pendingStateNum","internalType":"uint64"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"createNewRollup","inputs":[{"type":"uint32","name":"rollupTypeID","internalType":"uint32"},{"type":"uint64","name":"chainID","internalType":"uint64"},{"type":"address","name":"admin","internalType":"address"},{"type":"address","name":"sequencer","internalType":"address"},{"type":"address","name":"gasTokenAddress","internalType":"address"},{"type":"string","name":"sequencerURL","internalType":"string"},{"type":"string","name":"networkName","internalType":"string"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"deactivateEmergencyState","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getBatchFee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getForcedBatchFee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes","name":"","internalType":"bytes"}],"name":"getInputSnarkBytes","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32"},{"type":"uint64","name":"initNumBatch","internalType":"uint64"},{"type":"uint64","name":"finalNewBatch","internalType":"uint64"},{"type":"bytes32","name":"newLocalExitRoot","internalType":"bytes32"},{"type":"bytes32","name":"oldStateRoot","internalType":"bytes32"},{"type":"bytes32","name":"newStateRoot","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"","internalType":"uint64"}],"name":"getLastVerifiedBatch","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getRoleAdmin","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getRollupBatchNumToStateRoot","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32"},{"type":"uint64","name":"batchNum","internalType":"uint64"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getRollupExitRoot","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct LegacyZKEVMStateVariables.PendingState","components":[{"type":"uint64","name":"timestamp","internalType":"uint64"},{"type":"uint64","name":"lastVerifiedBatch","internalType":"uint64"},{"type":"bytes32","name":"exitRoot","internalType":"bytes32"},{"type":"bytes32","name":"stateRoot","internalType":"bytes32"}]}],"name":"getRollupPendingStateTransitions","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32"},{"type":"uint64","name":"batchNum","internalType":"uint64"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct LegacyZKEVMStateVariables.SequencedBatchData","components":[{"type":"bytes32","name":"accInputHash","internalType":"bytes32"},{"type":"uint64","name":"sequencedTimestamp","internalType":"uint64"},{"type":"uint64","name":"previousLastBatchSequenced","internalType":"uint64"}]}],"name":"getRollupSequencedBatches","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32"},{"type":"uint64","name":"batchNum","internalType":"uint64"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IPolygonZkEVMGlobalExitRootV2"}],"name":"globalExitRootManager","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"grantRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"trustedAggregator","internalType":"address"},{"type":"uint64","name":"_pendingStateTimeout","internalType":"uint64"},{"type":"uint64","name":"_trustedAggregatorTimeout","internalType":"uint64"},{"type":"address","name":"admin","internalType":"address"},{"type":"address","name":"timelock","internalType":"address"},{"type":"address","name":"emergencyCouncil","internalType":"address"},{"type":"address","name":"","internalType":"contract PolygonZkEVMExistentEtrog"},{"type":"address","name":"","internalType":"contract IVerifierRollup"},{"type":"uint64","name":"","internalType":"uint64"},{"type":"uint64","name":"","internalType":"uint64"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isEmergencyState","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isPendingStateConsolidable","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32"},{"type":"uint64","name":"pendingStateNum","internalType":"uint64"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"","internalType":"uint64"}],"name":"lastAggregationTimestamp","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"","internalType":"uint64"}],"name":"lastDeactivatedEmergencyStateTimestamp","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint16","name":"","internalType":"uint16"}],"name":"multiplierBatchFee","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"obsoleteRollupType","inputs":[{"type":"uint32","name":"rollupTypeID","internalType":"uint32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint64","name":"","internalType":"uint64"}],"name":"onSequenceBatches","inputs":[{"type":"uint64","name":"newSequencedBatches","internalType":"uint64"},{"type":"bytes32","name":"newAccInputHash","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"overridePendingState","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32"},{"type":"uint64","name":"initPendingStateNum","internalType":"uint64"},{"type":"uint64","name":"finalPendingStateNum","internalType":"uint64"},{"type":"uint64","name":"initNumBatch","internalType":"uint64"},{"type":"uint64","name":"finalNewBatch","internalType":"uint64"},{"type":"bytes32","name":"newLocalExitRoot","internalType":"bytes32"},{"type":"bytes32","name":"newStateRoot","internalType":"bytes32"},{"type":"bytes32[24]","name":"proof","internalType":"bytes32[24]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"","internalType":"uint64"}],"name":"pendingStateTimeout","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20Upgradeable"}],"name":"pol","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"proveNonDeterministicPendingState","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32"},{"type":"uint64","name":"initPendingStateNum","internalType":"uint64"},{"type":"uint64","name":"finalPendingStateNum","internalType":"uint64"},{"type":"uint64","name":"initNumBatch","internalType":"uint64"},{"type":"uint64","name":"finalNewBatch","internalType":"uint64"},{"type":"bytes32","name":"newLocalExitRoot","internalType":"bytes32"},{"type":"bytes32","name":"newStateRoot","internalType":"bytes32"},{"type":"bytes32[24]","name":"proof","internalType":"bytes32[24]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revokeRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"rollbackBatches","inputs":[{"type":"address","name":"rollupContract","internalType":"contract IPolygonRollupBase"},{"type":"uint64","name":"targetBatch","internalType":"uint64"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"rollupID","internalType":"uint32"}],"name":"rollupAddressToID","inputs":[{"type":"address","name":"rollupAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"rollupCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"rollupContract","internalType":"contract IPolygonRollupBase"},{"type":"uint64","name":"chainID","internalType":"uint64"},{"type":"address","name":"verifier","internalType":"contract IVerifierRollup"},{"type":"uint64","name":"forkID","internalType":"uint64"},{"type":"bytes32","name":"lastLocalExitRoot","internalType":"bytes32"},{"type":"uint64","name":"lastBatchSequenced","internalType":"uint64"},{"type":"uint64","name":"lastVerifiedBatch","internalType":"uint64"},{"type":"uint64","name":"lastPendingState","internalType":"uint64"},{"type":"uint64","name":"lastPendingStateConsolidated","internalType":"uint64"},{"type":"uint64","name":"lastVerifiedBatchBeforeUpgrade","internalType":"uint64"},{"type":"uint64","name":"rollupTypeID","internalType":"uint64"},{"type":"uint8","name":"rollupCompatibilityID","internalType":"uint8"}],"name":"rollupIDToRollupData","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32","name":"","internalType":"uint32"}],"name":"rollupTypeCount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"consensusImplementation","internalType":"address"},{"type":"address","name":"verifier","internalType":"contract IVerifierRollup"},{"type":"uint64","name":"forkID","internalType":"uint64"},{"type":"uint8","name":"rollupCompatibilityID","internalType":"uint8"},{"type":"bool","name":"obsolete","internalType":"bool"},{"type":"bytes32","name":"genesis","internalType":"bytes32"}],"name":"rollupTypeMap","inputs":[{"type":"uint32","name":"rollupTypeID","internalType":"uint32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBatchFee","inputs":[{"type":"uint256","name":"newBatchFee","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMultiplierBatchFee","inputs":[{"type":"uint16","name":"newMultiplierBatchFee","internalType":"uint16"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setPendingStateTimeout","inputs":[{"type":"uint64","name":"newPendingStateTimeout","internalType":"uint64"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setTrustedAggregatorTimeout","inputs":[{"type":"uint64","name":"newTrustedAggregatorTimeout","internalType":"uint64"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setVerifyBatchTimeTarget","inputs":[{"type":"uint64","name":"newVerifyBatchTimeTarget","internalType":"uint64"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"","internalType":"uint64"}],"name":"totalSequencedBatches","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"","internalType":"uint64"}],"name":"totalVerifiedBatches","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"","internalType":"uint64"}],"name":"trustedAggregatorTimeout","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateRollup","inputs":[{"type":"address","name":"rollupContract","internalType":"contract ITransparentUpgradeableProxy"},{"type":"uint32","name":"newRollupTypeID","internalType":"uint32"},{"type":"bytes","name":"upgradeData","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateRollupByRollupAdmin","inputs":[{"type":"address","name":"rollupContract","internalType":"contract ITransparentUpgradeableProxy"},{"type":"uint32","name":"newRollupTypeID","internalType":"uint32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint64","name":"","internalType":"uint64"}],"name":"verifyBatchTimeTarget","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"verifyBatches","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32"},{"type":"uint64","name":"pendingStateNum","internalType":"uint64"},{"type":"uint64","name":"initNumBatch","internalType":"uint64"},{"type":"uint64","name":"finalNewBatch","internalType":"uint64"},{"type":"bytes32","name":"newLocalExitRoot","internalType":"bytes32"},{"type":"bytes32","name":"newStateRoot","internalType":"bytes32"},{"type":"address","name":"beneficiary","internalType":"address"},{"type":"bytes32[24]","name":"proof","internalType":"bytes32[24]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"verifyBatchesTrustedAggregator","inputs":[{"type":"uint32","name":"rollupID","internalType":"uint32"},{"type":"uint64","name":"pendingStateNum","internalType":"uint64"},{"type":"uint64","name":"initNumBatch","internalType":"uint64"},{"type":"uint64","name":"finalNewBatch","internalType":"uint64"},{"type":"bytes32","name":"newLocalExitRoot","internalType":"bytes32"},{"type":"bytes32","name":"newStateRoot","internalType":"bytes32"},{"type":"address","name":"beneficiary","internalType":"address"},{"type":"bytes32[24]","name":"proof","internalType":"bytes32[24]"}]}]
Contract Creation Code
0x60e0346200018e57601f6200536638819003918201601f19168301916001600160401b0383118484101762000193578084926060946040528339810103126200018e5780516001600160a01b03919082811681036200018e5760208201519183831683036200018e576040015192831683036200018e5760805260c05260a05260005460ff8160081c16620001395760ff80821610620000fd575b6040516151bc9081620001aa8239608051818181610c140152818161180c015281816127b6015281816129230152614080015260a051818181610a0801528181610e6301526143f6015260c0518181816105e301528181613bcb01526147ee0152f35b60ff90811916176000557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160ff8152a1386200009a565b60405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b6064820152608490fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe60808060405260043610156200001457600080fd5b600090813560e01c9081630645af091462002b2057508063066ec0121462002af7578063080b31111462002aa75780630a0d9fbe1462002a7b57806311f6b2871462002a3057806312b86e1914620028955780631489ed10146200272657806315064c9614620027015780631608859c146200264a5780631796a1ae14620026245780631816b7e514620025775780632072f6c514620024a3578063248a9ca314620024745780632528016914620023be5780632f2ff15d146200231557806330c27dde14620022ec57806336568abe146200229d578063394218e914620021e8578063477fa27014620021c857806355a71ee0146200216b57806360469169146200212157806365c0504d146200209b5780637222020f1462001fc4578063727885e91462001b865780637975fcfe1462001b0d5780637fb6e76a1462001acb578063841b24d71462001aa857806387c20c0114620015d75780638bd4f071146200153e5780638fd88cc2146200120057806391d1485414620011b057806399f5634e14620011915780639a908e7314620010265780639c9f3dfe1462000f80578063a066215c1462000ed7578063a217fddf1462000eb9578063a2967d991462000e92578063a3c573eb1462000e4b578063afd23cbe1462000e24578063b99d0ad71462000d59578063c1acbc341462000d2d578063c4c928c21462000c87578063ceee281d1462000c43578063d02103ca1462000bfc578063d5073f6f1462000b41578063d547741f1462000afb578063d939b3151462000ad2578063dbc16976146200099e578063dde0ff771462000972578063dfdb8c5e1462000823578063e0bfd3d21462000612578063e46761c414620005cb578063f34eb8eb14620003ad578063f4e9267514620003875763f9c4c2ae14620002b657600080fd5b3462000384576020366003190112620003845760406101809163ffffffff620002de62003468565b16815260816020522060ff815491600181015460058201549160076006820154910154926040519560018060a01b039384821688526001600160401b039485809360a01c1660208a01528116604089015260a01c166060870152608086015281811660a0860152818160401c1660c0860152818160801c1660e086015260c01c6101008501528082166101208501528160401c1661014084015260801c16610160820152f35b80fd5b50346200038457806003193601126200038457602063ffffffff60805416604051908152f35b5034620003845760c03660031901126200038457620003cb620033c7565b620003d56200340c565b90620003e06200343a565b906064359160ff8316809303620005c65760843560a435936001600160401b0394858111620005c2576200041990369060040162003666565b3360009081527fb3124b64d0942b276d75ea451f4dd8b83bf9442b427f9eb873ac771c92e65f02602052604090205490939060ff1615620005b057607e549663ffffffff6200046a818a16620036d3565b16809863ffffffff191617607e556040519060c0820190828210898311176200059a5789916040528a600160a01b6001900380991698898552806020860193169a8b84528060408701971696878152606087019289845280608089019580875260a08a01988d8a528152607f60205260409020985116906001600160601b0360a01b91828a541617895560018901965116908654161785555116620005109084620036ff565b519082549060ff60e81b9051151560e81b169160ff60e01b9060e01b169061ffff60e01b1916171790555190600201556040519586958652602086015260408501526060840152608083015260a0820160c0905260c082016200057391620036ac565b037fa2970448b3bd66ba7e524e7b2a5b9cf94fa29e32488fb942afdfe70dd4b77b5291a280f35b634e487b7160e01b600052604160045260246000fd5b604051637615be1f60e11b8152600490fd5b8780fd5b600080fd5b503462000384578060031936011262000384576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5034620003845760c0366003190112620003845762000630620033c7565b6200063a6200340c565b90620006456200343a565b606435906001600160401b03808316808403620005c65760a4359560ff871692838803620005c6573360009081527ff444741efd45fa05f38650e87f3d8ca01816575bed45a01e78186ae5f3bc8355602090815260409091205490989060ff1615620005b057838a526083895263ffffffff968760408c2054166200081157878511620007ff576001600160a01b03988916808c5260828b5260408c20549094908916620007ed5760805498620006fe818b16620036d3565b16988963ffffffff1980921617608055868d5260838c5260408d208a82825416179055898d8d888252608290526040902091825416179055888c5260818b5260408c20996001600160601b0360a01b9086828d5416178c5560018c0192620007678b85620036ff565b16908254161790556200077b9089620036ff565b60078801805460ff60801b191660809290921b60ff60801b1691909117905560405194168452868401526040830152606082015284608082015260a07fadfc7d56f7e39b08b321534f14bfb135ad27698f7d2f5ad0edc2356ea9a3f85091a28280526002019052608435604082205580f35b604051630d409b9360e41b8152600490fd5b604051634c753f5760e01b8152600490fd5b6040516337c8fe0960e11b8152600490fd5b503462000384576040366003190112620003845762000841620033c7565b6200084b6200347c565b6040516303e1469160e61b81529091906001600160a01b03808316919060208260048189875af19182156200096757869262000930575b50339116036200091e578352608260205263ffffffff8060408520541684526081602052604084206006810154906001600160401b039182808260401c169116036200090c576007015460401c169083161115620008fa57620008f79160405191620008ee83620035d0565b84835262003773565b80f35b604051633e37e23360e01b8152600490fd5b60405163664316a560e11b8152600490fd5b60405163696072e960e01b8152600490fd5b6200095791925060203d81116200095f575b6200094e8183620035ec565b81019062003752565b903862000882565b503d62000942565b6040513d88823e3d90fd5b5034620003845780600319360112620003845760206001600160401b0360845460401c16604051908152f35b503462000384578060031936011262000384573360009081527f307dd781c86f141a460373e0117a8033afea21c02f6121aff0f5b5553df24f4a602052604090205460ff1615620005b0576087805467ffffffffffffffff1916426001600160401b0316179055807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1562000acf57818091600460405180948193636de0b4bb60e11b83525af1801562000ac45762000aac575b5050606f5460ff81161562000a9a5760ff1916606f557f1e5e34eea33501aecf2ebec9fe0e884a40804275ea7fe10b2ba084c8374308b38180a180f35b604051635386698160e01b8152600490fd5b62000ab79062003584565b6200038457803862000a5d565b6040513d84823e3d90fd5b50fd5b5034620003845780600319360112620003845760206001600160401b0360855416604051908152f35b5034620003845760403660031901126200038457620008f760043562000b206200340c565b90808452603460205262000b3b600160408620015462004aab565b62004ad0565b50346200038457602036600319011262000384573360009081527fe0205af17734f857fb538b40523c7cc189a1ab8f1ec33be516761c6b465766b660205260409020546004359060ff1615620005b057683635c9adc5dea000008111801562000bee575b62000bdc576020817ffb383653f53ee079978d0c9aff7aeff04a10166ce244cca9c9f9d8d96bed45b292608655604051908152a180f35b604051638586952560e01b8152600490fd5b50633b9aca00811062000ba5565b503462000384578060031936011262000384576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503462000384576020366003190112620003845760209063ffffffff906040906001600160a01b0362000c75620033c7565b16815260828452205416604051908152f35b503462000384576060366003190112620003845762000ca5620033c7565b62000caf6200347c565b6044356001600160401b03811162000d29573660238201121562000d295762000ce39036906024816004013591016200362a565b3360009081527ff14f5a8ad59d90593602e905b358229bff5ceea677d5bf0f5a1701793550a9a6602052604090205490919060ff1615620005b057620008f79262003773565b8380fd5b5034620003845780600319360112620003845760206001600160401b0360845460801c16604051908152f35b5034620003845760403660031901126200038457608090604062000d7c62003468565b9163ffffffff62000d8c62003423565b93826060855162000d9d81620035b4565b8281528260208201528287820152015216815260816020526004828220016001600160401b038094168252602052206040519062000ddb82620035b4565b8054928084169384845281602085019160401c16815260606002600185015494604087019586520154940193845260405194855251166020840152516040830152516060820152f35b50346200038457806003193601126200038457602061ffff60855460801c16604051908152f35b503462000384578060031936011262000384576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346200038457806003193601126200038457602062000eb162004528565b604051908152f35b50346200038457806003193601126200038457602090604051908152f35b503462000384576020366003190112620003845762000ef562003451565b62000eff62004a71565b6001600160401b0381169062015180821162000f6e57608580546fffffffffffffffff00000000000000001916604092831b67ffffffffffffffff60401b16179055519081527f1b023231a1ab6b5d93992f168fb44498e1a7e64cef58daff6f1c216de6a68c2890602090a180f35b604051631c0cfbfd60e31b8152600490fd5b503462000384576020366003190112620003845762000f9e62003451565b62000fa862004a71565b60ff606f54161562000ffe575b60206001600160401b037fc4121f4e22c69632ebb7cf1f462be0511dc034f999b52013eddfb24aab765c759216806001600160401b03196085541617608555604051908152a180f35b6001600160401b0380608554169082161062000fb55760405163048a05a960e41b8152600490fd5b50346200038457604036600319011262000384576200104462003451565b60ff606f54166200117f573382526020916082835263ffffffff6040822054169081156200116d576001600160401b03808416156200115b5762001124604083856200112a95526081885220916084549080620010a488828516620039bc565b16966001600160401b031997888094161760845560068501805483620010ce8183169485620039bc565b16998a911617905560405192620010e58462003598565b60243584528260018b8601958242168752604081019485528b600052600389018d5260406000209051815501945116908454161783555116906200372a565b62003f32565b7f1d9f30260051d51d70339da239ea7b080021adcaabfa71c9b0ea339a20cf9a2583604051848152a2604051908152f35b604051632590ccf960e01b8152600490fd5b6040516371653c1560e01b8152600490fd5b604051630bc011ff60e21b8152600490fd5b50346200038457806003193601126200038457602062000eb1620047d3565b50346200038457604036600319011262000384576040620011d06200340c565b9160043581526034602052209060018060a01b0316600052602052602060ff604060002054166040519015158152f35b50346200038457604036600319011262000384576200121e620033c7565b906200122962003423565b917f66156603fe29d13f97c6f3e3dff4ef71919f9aa61c555be0182d954e94221aac8252602090603482526040832033600052825260ff604060002054161580620014d3575b620014c15760018060a01b0316928383526082825263ffffffff604084205416918215620014af5782845260818152604084209160068301938454966001600160401b03958689168785169988828c10918215926200149f575b50506200148d57600387019688825b168b81146200132d57806000528888526001908a826040600020015460401c16908d82106200131b578b928d916000528b8b5260406000208281550155620012d8565b604051639753965f60e01b8152600490fd5b50620013538a9b9a9699939495996001600160401b0319938c8588541617875562003987565b9280620013666084549582871662003987565b16809385161780608455855491808360801c1662001427575b5050505050505085600052838352604060002054813b156200142357829160448392604051948593849263334d6f6760e11b84528c600485015260248401525af1801562000ac45762001407575b50507f80a6d395a55aed8126079cb8247f0a6848b1440ca2cdca3b4386f250c352940291846000528152604060002054604051908152a380f35b620014129062003584565b6200141f578438620013cd565b8480fd5b8280fd5b620014546200145f93826200144867ffffffffffffffff60401b9762004761565b9160401c169062003987565b9160401c1662003987565b60401b16916001600160801b03191617176084556001600160801b038154169055388080808080806200137f565b60405163cb23ebdf60e01b8152600490fd5b60401c168b1090508838620012c9565b6040516374a086a360e01b8152600490fd5b604051630d03687f60e11b8152600490fd5b506040516303e1469160e61b81526001600160a01b038382600481888786165af1918215620015335785926200150f575b50163314156200126f565b6200152b919250843d86116200095f576200094e8183620035ec565b903862001504565b6040513d87823e3d90fd5b50346200038457620015503662003490565b969592919360ff606f96929654166200117f577f1f44c21118c4603cfb4e1b621dbcfa2b73efcececee2b99b620b2953d33a701097866004966001600160401b0395620015b3948660408f63ffffffff829f168152608160205220998a62004179565b16865201602052600282852001549082519182526020820152a1620008f7620043f4565b50346200038457620015e93662003506565b9060ff606f9897989693959654166200117f5763ffffffff87168952608160205260408920976001600160401b03871660005260038901602052620016466001600160401b036001604060002001541660845460c01c90620039bc565b6001600160401b034291161162001a96576103e86001600160401b036200166e868a62003987565b161162001a84578487620016859588938c62003a2e565b620016908562004761565b94839587906001600160401b03620016a9828862003987565b169060855492620016c76001600160401b038560401c1642620043c5565b995b6001600160401b0383166001600160401b0382161462001a6e576001600160401b03811660005260038601602052600160406000200154906001600160401b0382168c1060001462001728575060401c6001600160401b0316620016c9565b620017559495969798999a9b506200174c92506001600160401b0393915062003987565b168092620043c5565b918183101562001a12575003600c81111562001a0757506200178f600c5b6086548161ffff60855460801c160a02906103e80a90620043d3565b6086555b608654683635c9adc5dea000009081811115620019e657506086555b6085546001600160401b0316620018f3578160056006830192620017d487856200372a565b6001600160401b0387166000526002810160205285604060002055015580546001600160401b038160801c16620018e0575b508590507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166200183e62004528565b813b15620014235782916024839260405194859384926333d6247d60e01b845260048401525af1801562000ac457620018c8575b50507faac1e7a157b259544ebacd6e8a82ae5d6c8f174e12aa48696277bcc9a661f0b4915b604080516001600160401b0390951685526020850191909152830152339263ffffffff169180606081015b0390a380f35b620018d39062003584565b6200141f57843862001872565b6001600160801b03169055388062001806565b620019018193929362003f32565b6006810180546001600160401b038160801c166001600160401b038114620019d2579385620019c26001600160401b03898160408e6004889b847faac1e7a157b259544ebacd6e8a82ae5d6c8f174e12aa48696277bcc9a661f0b49f9e9c60029c60609e60018460801b910160801b16908360801b19161780915585519d8e6200198b81620035b4565b834216815283602082019a168a528781019c8d52019b8c5260801c168352016020522097511682198854161787555116856200372a565b5160018401555191015562001897565b634e487b7160e01b89526011600452602489fd5b9050633b9aca00809110620019fd575b50620017af565b60865538620019f6565b6200178f9062001773565b9062001a599203600c811160001462001a62575062001a4e600c915b670de0b6b3a76400009261ffff816103e80a9260801c160a8302620043d3565b9060865402620043d3565b60865562001793565b62001a4e909162001a2e565b50929394959697985050816200175591620043c5565b604051635acfba9d60e11b8152600490fd5b604051638a0704d360e01b8152600490fd5b50346200038457806003193601126200038457602060845460c01c604051908152f35b503462000384576020366003190112620003845763ffffffff60406020926001600160401b0362001afb62003451565b16815260838452205416604051908152f35b5034620003845760c0366003190112620003845762001b6d62001b829162001b3462003468565b9062001b3f62003423565b9063ffffffff62001b4f6200343a565b93168152608160205260a4359260843592604060643593206200489f565b604051918291602083526020830190620036ac565b0390f35b5034620003845760e0366003190112620003845762001ba462003468565b9062001baf62003423565b60443592906001600160a01b0384168403620005c65762001bcf620033de565b9062001bda620033f5565b9060a4356001600160401b03811162001fc05762001bfd90369060040162003666565b9260c4356001600160401b03811162001fbc5762001c2090369060040162003666565b3360009081527f41902c3bd358ff4b85ee46864bd81ee453a1b3cfd703a58950be8d28ae030661602052604090205460ff1615620005b05763ffffffff861615801562001fa4575b62001f925763ffffffff86168752607f6020526040872097600160ff818b015460e81c1615151462001f805763ffffffff6001600160401b03851611620007ff576001600160401b0384168852608360205263ffffffff60408920541662000811576080549463ffffffff62001ce0818816620036d3565b1663ffffffff1996909616861760805589546040519a906001600160a01b031662001d0b8c620035d0565b8a8c52604051908161061f8101106001600160401b0361061f8401111762001f6c5762001d5d8c9d839261061f62004b48853961061f84019081523060208201526060604082018190520190620036ac565b03908bf095861562001f615787926001600160401b038262001e828d8f60017f194c983456df6701c6a50830b90fe80e72b823411d0d524970c9590dc277a6419862001e5f8f600763ffffffff9160ff968f8c60809f168252608360205260408220818619825416179055878060a01b03831682526082602052604082208186198254161790558152608160205260408120916001600160601b0360a01b90888060a01b0316818454161783558c8888015460a01c169062001e238985019283620036ff565b888060a01b0389890154169082541617905562001e418b83620036ff565b6040600287015491808052600284016020522055019516856200372a565b0154825460ff60801b191660e09190911c9190911660801b60ff60801b16179055565b63ffffffff6040519d168d528c602060018060a01b038c169101521660408c015260018060a01b0316998a6060820152a26001600160a01b0384163b15620005c257604051633892b81160e11b81526001600160a01b039182166004820152921660248301526044820193909352606481019490945260c060848501528492849283918591839162001f32919062001f1f9060c4850190620036ac565b8381036003190160a485015290620036ac565b03926001600160a01b03165af1801562000ac45762001f4e5750f35b62001f599062003584565b620003845780f35b6040513d8c823e3d90fd5b634e487b7160e01b8c52604160045260248cfd5b604051633b8d3d9960e01b8152600490fd5b604051637512e5cb60e01b8152600490fd5b5063ffffffff607e541663ffffffff87161162001c68565b8680fd5b8580fd5b503462000384576020366003190112620003845762001fe262003468565b3360009081527fd26c1f3d72948c9f5ca2b28d010847694e18f81d42613c046515d0839b64354c602052604090205460ff1615620005b05763ffffffff8091169081159081156200208c575b5062001f9257808252607f602052600160408320018054600160ff8260e81c1615151462001f805760ff60e81b1916600160e81b1790557f4710d2ee567ef1ed6eb2f651dde4589524bcf7cebc62147a99b281cc836e7e448280a280f35b9050607e54168111386200202e565b5034620003845760203660031901126200038457604060c09163ffffffff620020c362003468565b168152607f6020522060018060a01b0360ff81835416926002600182015491015492604051948552811660208501526001600160401b038160a01c166040850152818160e01c16606085015260e81c161515608083015260a0820152f35b50346200038457806003193601126200038457608654906064820291808304606414901517156200215757602082604051908152f35b634e487b7160e01b81526011600452602490fd5b50346200038457604036600319011262000384576001600160401b03600260406200219562003468565b9363ffffffff620021a562003423565b951681526081602052200191166000526020526020604060002054604051908152f35b503462000384578060031936011262000384576020608654604051908152f35b50346200038457602036600319011262000384576200220662003451565b6200221062004a71565b60ff606f54161562002275575b608480546001600160c01b031660c083901b6001600160c01b0319161790556040516001600160401b0390911681527f1f4fa24c2e4bad19a7f3ec5c5485f70d46c798461c2e684f55bbd0fc661373a190602090a180f35b60845460c01c6001600160401b038216106200221d5760405163401636df60e01b8152600490fd5b5034620003845760403660031901126200038457620022bb6200340c565b336001600160a01b03821603620022da57620008f79060043562004ad0565b604051630b4ad1cd60e31b8152600490fd5b5034620003845780600319360112620003845760206001600160401b0360875416604051908152f35b5034620003845760403660031901126200038457600435620023366200340c565b818352603460205262002350600160408520015462004aab565b8183526034602052604083209060018060a01b0316908160005260205260ff604060002054161562002380578280f35b818352603460205260408320816000526020526040600020600160ff198254161790553391600080516020620051678339815191528480a438808280f35b503462000384576040366003190112620003845760609060036040620023e362003468565b9263ffffffff620023f362003423565b9482848051620024038162003598565b8281528260208201520152168152608160205220016001600160401b038092166000526020526040600020906040516200243d8162003598565b81600184549485845201549181604060208301928286168452019360401c1683526040519485525116602084015251166040820152f35b503462000384576020366003190112620003845760016040602092600435815260348452200154604051908152f35b503462000384578060031936011262000384577f141f8f32ce6198eee741f695cec728bfd32d289f1acf73621fb303581000545e81526034602052604081203360005260205260ff604060002054161562002503575b620008f7620043f4565b6001600160401b038060845460801c169081159182156200255d575b50811562002541575b5015620024f95760405163692baaad60e11b8152600490fd5b9050620025528160875416620039a1565b429116113862002528565b6200256a919250620039a1565b814291161190386200251f565b503462000384576020366003190112620003845760043561ffff8116908181036200142357620025a662004a71565b6103e88210801562002618575b62002606576085805461ffff60801b191660809290921b61ffff60801b169190911790556040519081527f7019933d795eba185c180209e8ae8bffbaa25bcef293364687702c31f4d302c590602090a180f35b604051630984a67960e31b8152600490fd5b506103ff8211620025b3565b50346200038457806003193601126200038457602063ffffffff607e5416604051908152f35b50346200038457604036600319011262000384576200266862003468565b63ffffffff6200267762003423565b91168252608160205260408220907f084e94f375e9d647f87f5b2ceffba1e062c70f6009fdbcf80291e803b5c9edd483526034602052604083203360005260205260ff6040600020541615620026d3575b620008f79162003fdc565b60ff606f54166200117f57620026ea81836200479e565b620026c857604051630674f25160e11b8152600490fd5b50346200038457806003193601126200038457602060ff606f54166040519015158152f35b503462000384576200276f63ffffffff620027413662003506565b9284819796998499620027599c979c95949562004a37565b16998a8d52608160205260408d20978862003a2e565b60068101906200278086836200372a565b8260056001600160401b0392838916600052600281016020528660406000205501558154908160801c1662002882575b508590507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316620027e862004528565b813b15620014235782916024839260405194859384926333d6247d60e01b845260048401525af1801562000ac4576200286a575b5050604080516001600160401b03909516855260208501929092529083015233917fd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3908060608101620018c2565b620028759062003584565b6200141f5784386200281c565b6001600160801b031690553880620027b0565b50346200038457620028dd63ffffffff620028b03662003490565b92809599948297998499620028c795949562004a37565b169a8b8d52608160205260408d209a8b62004179565b6006840190620028ee81836200372a565b8360056001600160401b0380931696878a52600281016020528560408b205501558154908160801c1662002a1d575b508590507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166200295562004528565b90803b1562001423576024839260405194859384926333d6247d60e01b845260048401525af180156200096757620029e0575b50608480546001600160c01b031661127560c71b1790556040805193845260208401919091528201523360608201527f3182bd6e6f74fc1fdc88b60f3a4f4c7f79db6ae6f5b88a1b3f5a1e28ec210d5e90608090a280f35b917f3182bd6e6f74fc1fdc88b60f3a4f4c7f79db6ae6f5b88a1b3f5a1e28ec210d5e93919562002a1260809462003584565b959193509162002988565b6001600160801b0316905538806200291d565b503462000384576020366003190112620003845762002a6a604060209263ffffffff62002a5c62003468565b168152608184522062004761565b6001600160401b0360405191168152f35b5034620003845780600319360112620003845760206001600160401b0360855460401c16604051908152f35b503462000384576040366003190112620003845762002aed602091604062002ace62003468565b9163ffffffff62002ade62003423565b9316815260818552206200479e565b6040519015158152f35b5034620003845780600319360112620003845760206001600160401b0360845416604051908152f35b905034620033c357610140366003190112620033c35762002b40620033c7565b62002b4a62003423565b62002b546200343a565b62002b5e620033de565b62002b68620033f5565b6001600160a01b039360a435858116949190859003620033bf5760c43586811603620033bf5760e43586811603620033bf576001600160401b03906101043582811603620033bb576101243582811603620033bb57895460ff998a8260081c161580620033ae575b1562003355575061ffff191661010217808b5560858054608480546001600160c01b031660c09790971b6001600160c01b0319169690961790955567016345785d8a00006086556fffffffffffffffffffffffffffffffff19909416929091169190911769070800000000000000001761ffff60801b19166101f560811b1790915560081c861615620032fc577f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498957f084e94f375e9d647f87f5b2ceffba1e062c70f6009fdbcf80291e803b5c9edd4948589526034926020978489528260408c20911690818c5289528360408c20541615620032c2575b508980528388528160408b20911690818b5288528260408b2054161562003289575b7fac75d24dbb35ea80e25fab167da4dea46c1915260426570db84f184891f5f590808b5284895260408b20828c5289528360408c205416156200324e575b507f3dfe277d2a2c04b75fb2eb3743fa00005ae3678a20c299e65fdf4df76517f68e808b5284895260408b20828c5289528360408c2054161562003213575b507f66156603fe29d13f97c6f3e3dff4ef71919f9aa61c555be0182d954e94221aac90818b5284895260408b20818c5289528360408c20541615620031d9575b50507fab66e11c4f712cd06ab11bf9339b48bef39e12d4a22eeef71d2860a0c90482bd90818a5283885260408a20941693848a5287528160408a205416156200319e575b507fa0fab074aba36a6fa69f1a83ee86e5abfb8433966eb57efb13dc2fc2f24ddd0880895282875260408920848a5287528160408a2054161562003163575b507f62ba6ba2ffed8cfe316b583325ea41ac6e7ba9e5864d2bc6fabba7ac26d2f0f480895282875260408920848a5287528160408a2054161562003128575b507fa5c5790f581d443ed43873ab47cfb8c5d66a6db268e58b5971bb33fc66e07db180895282875260408920848a5287528160408a20541615620030ed575b508488528186526001928360408a20018054907f73cb0569fdbea2544dae03fdb2fe10eda92a72a2e8cd2bd496e85b762505a3f091828092557fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff98898d80a4808a5260408a20828b5288528260408b20541615620030b3575b507f8cf807f6970720f8e2c208c7c5037595982c7bd9ed93c380d09df743d0dcc3fb90818a5283885260408a20818b5288528260408b205416156200307a575b50507f141f8f32ce6198eee741f695cec728bfd32d289f1acf73621fb303581000545e808952828752604089208481018054837f9b6f082d8d3644ae2f24a3c32e356d6f2d9b2844d9b26164fbc82663ff285951998a8094558d80a4858a5287528160408a2054161562003040575b508488528186526040882084895286526040882054161562003005575b5050845461ff0019168555505060405160028152a180f35b8387528452604086208287528452604086209060ff198254161790553391600080516020620051678339815191528680a43880808062002fed565b80895282875260408920858a528752604089208460ff19825416179055843391600080516020620051678339815191528b80a43862002fd0565b818a528388526040808b20828c5289528a20805460ff1916861790553391600080516020620051678339815191528b80a4388062002f61565b808a5283885260408a20828b52885260408a208560ff19825416179055813391600080516020620051678339815191528c80a43862002f21565b80895282875260408920848a52875260408920600160ff19825416179055833391600080516020620051678339815191528b80a43862002ea8565b80895282875260408920848a52875260408920600160ff19825416179055833391600080516020620051678339815191528b80a43862002e69565b80895282875260408920848a52875260408920600160ff19825416179055833391600080516020620051678339815191528b80a43862002e2a565b80895282875260408920848a52875260408920600160ff19825416179055833391600080516020620051678339815191528b80a43862002deb565b818b528489526040808c20828d528a528b20805460ff191660011790553391600080516020620051678339815191528c80a4388062002da7565b808b5284895260408b20828c52895260408b20600160ff19825416179055813391600080516020620051678339815191528d80a43862002d67565b808b5284895260408b20828c52895260408b20600160ff19825416179055813391600080516020620051678339815191528d80a43862002d28565b8980528388526040808b20828c5289528a20805460ff1916600117905533818b600080516020620051678339815191528180a462002cea565b878b528489526040808c20828d528a528b20805460ff19166001179055339088600080516020620051678339815191528d80a43862002cc8565b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b62461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b5060028b83161062002bd0565b8980fd5b8880fd5b5080fd5b600435906001600160a01b0382168203620005c657565b606435906001600160a01b0382168203620005c657565b608435906001600160a01b0382168203620005c657565b602435906001600160a01b0382168203620005c657565b602435906001600160401b0382168203620005c657565b604435906001600160401b0382168203620005c657565b600435906001600160401b0382168203620005c657565b6004359063ffffffff82168203620005c657565b6024359063ffffffff82168203620005c657565b6103e0600319820112620005c65760043563ffffffff81168103620005c657916001600160401b036024358181168103620005c657926044358281168103620005c657926064358381168103620005c657926084359081168103620005c6579160a4359160c435916103e411620005c65760e490565b6103e0600319820112620005c65760043563ffffffff81168103620005c657916001600160401b03906024358281168103620005c657926044358381168103620005c657926064359081168103620005c657916084359160a4359160c4356001600160a01b0381168103620005c657916103e411620005c65760e490565b6001600160401b0381116200059a57604052565b606081019081106001600160401b038211176200059a57604052565b608081019081106001600160401b038211176200059a57604052565b602081019081106001600160401b038211176200059a57604052565b90601f801991011681019081106001600160401b038211176200059a57604052565b6001600160401b0381116200059a57601f01601f191660200190565b92919262003638826200360e565b91620036486040519384620035ec565b829481845281830111620005c6578281602093846000960137010152565b9080601f83011215620005c65781602062003684933591016200362a565b90565b60005b8381106200369b5750506000910152565b81810151838201526020016200368a565b90602091620036c78151809281855285808601910162003687565b601f01601f1916010190565b63ffffffff809116908114620036e95760010190565b634e487b7160e01b600052601160045260246000fd5b805467ffffffffffffffff60a01b191660a09290921b67ffffffffffffffff60a01b16919091179055565b9067ffffffffffffffff60401b82549160401b169067ffffffffffffffff60401b1916179055565b90816020910312620005c657516001600160a01b0381168103620005c65790565b92919063ffffffff8091168015801562003979575b62001f925760018060a01b038095169460009580875260826020526040938488205416948515620039685785885260816020528488209260078401938454906001600160401b03908782848b1c16146200395757878c52607f602052888c209260018401805491600160ff8460e81c16151514620039465760ff808460e01c169160801c1603620039355782918462003841928860016006970193166001600160601b0360a01b8454161783555460a01c1690620036ff565b6200384d89896200372a565b0154818160c01c9160801c16036200392457908a93929189855260816020526200387989862062004761565b1695866001600160401b0319825416179055541692803b156200142357620038c49383885180968195829463278f794360e11b845260048401528b60248401526044830190620036ac565b03925af180156200391a577ff585e04c05d396901170247783d3e5f0ee9c1df23072985b50af089f5e48b19d9596975062003908575b5082519182526020820152a2565b620039139062003584565b38620038fa565b84513d89823e3d90fd5b8751639d59507b60e01b8152600490fd5b8a51635aa0d5f160e11b8152600490fd5b8b51633b8d3d9960e01b8152600490fd5b8851634f61d51960e01b8152600490fd5b84516374a086a360e01b8152600490fd5b5081607e5416811162003788565b6001600160401b039182169082160391908211620036e957565b9062093a806001600160401b0380931601918211620036e957565b9190916001600160401b0380809416911601918211620036e957565b90816020910312620005c657518015158103620005c65790565b9291906103208401936103008092823701906000915b6001831062003a1657505050565b60019082518152602080910192019201919062003a08565b9295909496939160009262003a438562004761565b916001600160401b03948560078801541698868316998a1062003e7d57861690811562003e37575085600688015460801c16811162003e2557600052600486016020526040600020978560028a0154995460401c160362003e13575b8489169785841689111562003e015762003abd928a8c93896200489f565b9060409788519260008480835162003adc816020998a80980162003687565b8101039060025afa1562003df65760005160018701548a516001600160a01b039962003b549387938c1691907f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001900662003b3684620035d0565b83528d51809581948293634890ed4560e11b845260048401620039f2565b03915afa90811562003deb5760009162003db7575b501562003da6579062003b7c9162003987565b9162003b87620047d3565b84841690818102918183041490151715620036e957885190878483019363a9059cbb60e01b855216602483015260448201526044815262003bc881620035b4565b867f0000000000000000000000000000000000000000000000000000000000000000168951918a8301838110888211176200059a578b528483527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564838601525162003c6893600091829182855af13d1562003d9d573d9162003c4a836200360e565b9262003c598d519485620035ec565b83523d60008785013e62003e8f565b80518062003d26575b50505062003c9367ffffffffffffffff60401b916084549384891c16620039bc565b77ffffffffffffffffffffffffffffffff00000000000000001990921691861b16174260801b67ffffffffffffffff60801b1617608455541692833b15620005c657606460009283855196879485936332c2d15360e01b8552600485015260248401523360448401525af190811562003d1c575062003d0f5750565b62003d1a9062003584565b565b513d6000823e3d90fd5b90828062003d39938301019101620039d8565b1562003d4757808062003c71565b60849087519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b60609162003e8f565b88516309bde33960e01b8152600490fd5b62003ddc9150843d861162003de3575b62003dd38183620035ec565b810190620039d8565b3862003b69565b503d62003dc7565b8a513d6000823e3d90fd5b88513d6000823e3d90fd5b60405163b9b18f5760e01b8152600490fd5b604051632bd2e3e760e01b8152600490fd5b60405163bb14c20560e01b8152600490fd5b6040915089815260028801602052205497881562003e6b57858416101562003a9f57604051630f2b74f160e11b8152600490fd5b6040516324cbdcc360e11b8152600490fd5b60405163ead1340b60e01b8152600490fd5b9192901562003ef4575081511562003ea5575090565b3b1562003eaf5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b82519091501562003f085750805190602001fd5b60405162461bcd60e51b81526020600482015290819062003f2e906024830190620036ac565b0390fd5b60068101546001600160401b0390818160801c169060c01c80821162003f59575b50505050565b600101918211620036e95762003f7082846200479e565b62003f7d575b8062003f53565b677fffffffffffffff62003f968362003fa19362003987565b60011c1682620039bc565b9062003fae82846200479e565b1562003fc9575062003fc09162003fdc565b38808062003f76565b905062003fd69162003fdc565b62003fc0565b9060068201908154906000936001600160401b039485831693868160c01c86119182159262004169575b5050620041575783815260048201602052604091828220968754841c16956200403087826200372a565b60028881018054898652918401602052858520919091556001989098018054600584015581546001600160c01b031660c09690961b6001600160c01b0319169590951790556001600160a01b03907f00000000000000000000000000000000000000000000000000000000000000008216620040ab62004528565b813b156200141f57849160248392885194859384926333d6247d60e01b845260048401525af180156200414d5793859363ffffffff9360809997937f581910eb7a27738945c2f00a91f2284b2d6de9d4e472b12f901c2b0df045e21b9b999762004137575b505416815260826020522054169654915491815194855260208501528301526060820152a2565b620041459093919362003584565b913862004110565b85513d86823e3d90fd5b60405163d086b70b60e01b8152600490fd5b60801c1685119050863862004006565b9192939496906000976001600160401b039889600786015416928a881693841062003e7d578a169081156200438b575089600686015460801c16811162003e255780600052600485016020526040600020928a6002850154945460401c160362003e13575b8960068601549616958a8160801c1687119182156200437f575b50811562004370575b506200435e5760048401968560005260209688885260409a808c600020548d1c16908316036200434d57898894600094620042559462004242948a6200489f565b838b519282848094519384920162003687565b8101039060025afa1562004342576000516001909201548751620042ce93869391926001600160a01b031691907f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000019006620042b084620035d0565b83528951809581948293634890ed4560e11b845260048401620039f2565b03915afa908115620043425760009162004320575b50156200430f5760005252600282600020015414620042ff5750565b5163a47276bd60e01b8152600490fd5b84516309bde33960e01b8152600490fd5b6200433b9150833d851162003de35762003dd38183620035ec565b38620042e3565b86513d6000823e3d90fd5b8a516332a2a77f60e01b8152600490fd5b60405163bfa7079f60e01b8152600490fd5b905060c01c8511153862004201565b871115915038620041f8565b80846040925260028701602052205492831562003e6b578a600687015460401c161015620041de57604051630f2b74f160e11b8152600490fd5b91908203918211620036e957565b8115620043de570490565b634e487b7160e01b600052601260045260246000fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15620005c6576040518091632072f6c560e01b82528160046000948580945af1801562000ac4576200448b575b50606f549060ff82166200117f5760017f2261efe5aef6fedc1fd1550b25facc9181745623049c7901287030b9ad1a54979260ff191617606f5580a1565b620044969062003584565b386200444d565b6001600160401b0381116200059a5760051b60200190565b90620044c1826200449d565b620044d06040519182620035ec565b8281528092620044e3601f19916200449d565b0190602036910137565b6000198114620036e95760010190565b8051821015620045125760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b63ffffffff806080541680156200475a576200454481620044b5565b9160005b828110620047235750509060006020915b600190818514620046ab578185811c951691828601809611620036e9576200458186620044b5565b9160009160001994858901898111945b8a8110620045d457505050505050939160408051906020820192808452818301528152620045bf8162003598565b519020928015620036e9570191909262004559565b85620036e95781811480620046a1575b15620046485780841b9080820460021481151715620036e9576200460d620046429287620044fd565b516040805190602082019283528c8183015281526200462c8162003598565b5190206200463b828a620044fd565b52620044ed565b62004591565b80841b9080820460021481151715620036e957620046678287620044fd565b51858301809311620036e95762004683620046429388620044fd565b516040805191602083019384528183015281526200462c8162003598565b50838314620045e4565b91935050805115620045125760200151916000905b828210620046ce5750505090565b6200471c906040948551602081019182528287820152868152620046f28162003598565b519020948051906020820192808452818301528152620047128162003598565b51902091620044ed565b90620046c0565b6001810190818111620036e9578262004754921660005260816020526005604060002001546200463b8287620044fd565b62004548565b5050600090565b60068101546001600160401b0391608082901c831680156200479557600492506000520160205260406000205460401c1690565b505060401c1690565b6004906001600160401b0380931660005201602052620047cb8160406000205416826085541690620039bc565b429116111590565b6040516370a0823160e01b81523060048201526020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811562004893576000916200485c575b50608454620048496001600160401b039182808260401c16911662003987565b1680156200475a576200368491620043d3565b906020823d82116200488a575b816200487860209383620035ec565b81010312620003845750513862004829565b3d915062004869565b6040513d6000823e3d90fd5b92939094916001600160401b039485871660009481865260038701602052604096878720549989861688528888205493151580620049bd575b620049ac5783156200499b57620048ef83620049c6565b156200498a579060749160018254920154918a519c8d993360601b60208c015260348b015260548a01526001600160401b0360c01b98899485809460c01b1691015260201b16607c8c015260201b1660848a0152608c89015260ac88015260cc87015260c01b1660ec85015260d48452610100840192848410908411176200497657505290565b634e487b7160e01b81526041600452602490fd5b88516305dae44f60e21b8152600490fd5b88516366385b5160e01b8152600490fd5b885163340c614f60e11b8152600490fd5b508a15620048d8565b67ffffffff000000016001600160401b03918183821610928362004a26575b8362004a14575b508262004a06575b50501562004a0157600190565b600090565b60c01c1090503880620049f4565b818392945060801c16109138620049ec565b925081838260401c161092620049e5565b3360009081527fc17b14a573f65366cdad721c7c0a0f76536bb4a86b935cdac44610e4f010b52a602052604090205460ff1615620005b057565b3360009081527f3b72b60ab7bcf7b6e5f79e30b28eb2a39d66a2a278905c2bfcfdd4e1c0a1907b602052604090205460ff1615620005b057565b600052603460205260406000203360005260205260ff6040600020541615620005b057565b906000918083526034602052604083209160018060a01b03169182845260205260ff60408420541662004b0257505050565b8083526034602052604083208284526020526040832060ff1981541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a456fe604060a0815261061f803803806100158161023b565b92833981016060828203126102365761002d82610276565b9060209161003c838501610276565b8585015190946001600160401b038211610236570182601f820112156102365780519061007061006b8361028a565b61023b565b9382855285838301011161023657849060005b83811061022257505060009184010152803b15610201577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b03199081166001600160a01b038481169182179093558751929691948794929390917fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a28151156101e0575090600080838861014695519101845af43d156101d8573d9161013761006b8461028a565b9283523d60008985013e6102a5565b505b8060805216917f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f857fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103958587549483519286168352820152a182156101c05716179055516103169081610309823960805181600f0152f35b8451633173bdd160e11b815260006004820152602490fd5b6060916102a5565b9293505050346101f257508390610148565b63b398979f60e01b8152600490fd5b8451634c9c8ce360e01b81526001600160a01b039091166004820152602490fd5b818101830151868201840152869201610083565b600080fd5b6040519190601f01601f191682016001600160401b0381118382101761026057604052565b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b038216820361023657565b6001600160401b03811161026057601f01601f191660200190565b906102cc57508051156102ba57805190602001fd5b604051630a12f52160e11b8152600490fd5b815115806102ff575b6102dd575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156102d556fe60806040526001600160a01b03337f00000000000000000000000000000000000000000000000000000000000000008216036100e05760009081356001600160e01b03191663278f794360e11b141582036100e057366004116100dc5760403660031901126100dc576004359081168091036100dc576024359067ffffffffffffffff82116100d857366023830112156100d85781600401356100a96100a48261016d565b610142565b9281845236602483830101116100d457816100d295926024602093018387013784010152610189565b005b8480fd5b8280fd5b5080fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54600090819081906001600160a01b0316368280378136915af43d82803e15610128573d90f35b3d90fd5b634e487b7160e01b600052604160045260246000fd5b6040519190601f01601f1916820167ffffffffffffffff81118382101761016857604052565b61012c565b67ffffffffffffffff811161016857601f01601f191660200190565b90813b15610221577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a28051156102065761020391610242565b50565b50503461020f57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b60008061027693602081519101845af43d15610279573d916102666100a48461016d565b9283523d6000602085013e61027d565b90565b6060915b906102a4575080511561029257805190602001fd5b604051630a12f52160e11b8152600490fd5b815115806102d7575b6102b5575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156102ad56fea2646970667358221220ddf15a6f4a4e94f45015fba958b16bfe0063f6be348dd5f915b909c5caee6cd064736f6c634300081400332f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0da264697066735822122037397a8e35cbdd5aefd144980560c0cefa434b2ab29a1d16fa4adfa2aac653a864736f6c63430008140033000000000000000000000000dbd32f81789bf2395d24d646a07a41639d9955fb000000000000000000000000429a1ed765b18e78f068e98e5ab1212a21aa131400000000000000000000000094a5c76eb7ab1ecd1ca43d637f9fc12b68a495d7
Deployed ByteCode
0x60808060405260043610156200001457600080fd5b600090813560e01c9081630645af091462002b2057508063066ec0121462002af7578063080b31111462002aa75780630a0d9fbe1462002a7b57806311f6b2871462002a3057806312b86e1914620028955780631489ed10146200272657806315064c9614620027015780631608859c146200264a5780631796a1ae14620026245780631816b7e514620025775780632072f6c514620024a3578063248a9ca314620024745780632528016914620023be5780632f2ff15d146200231557806330c27dde14620022ec57806336568abe146200229d578063394218e914620021e8578063477fa27014620021c857806355a71ee0146200216b57806360469169146200212157806365c0504d146200209b5780637222020f1462001fc4578063727885e91462001b865780637975fcfe1462001b0d5780637fb6e76a1462001acb578063841b24d71462001aa857806387c20c0114620015d75780638bd4f071146200153e5780638fd88cc2146200120057806391d1485414620011b057806399f5634e14620011915780639a908e7314620010265780639c9f3dfe1462000f80578063a066215c1462000ed7578063a217fddf1462000eb9578063a2967d991462000e92578063a3c573eb1462000e4b578063afd23cbe1462000e24578063b99d0ad71462000d59578063c1acbc341462000d2d578063c4c928c21462000c87578063ceee281d1462000c43578063d02103ca1462000bfc578063d5073f6f1462000b41578063d547741f1462000afb578063d939b3151462000ad2578063dbc16976146200099e578063dde0ff771462000972578063dfdb8c5e1462000823578063e0bfd3d21462000612578063e46761c414620005cb578063f34eb8eb14620003ad578063f4e9267514620003875763f9c4c2ae14620002b657600080fd5b3462000384576020366003190112620003845760406101809163ffffffff620002de62003468565b16815260816020522060ff815491600181015460058201549160076006820154910154926040519560018060a01b039384821688526001600160401b039485809360a01c1660208a01528116604089015260a01c166060870152608086015281811660a0860152818160401c1660c0860152818160801c1660e086015260c01c6101008501528082166101208501528160401c1661014084015260801c16610160820152f35b80fd5b50346200038457806003193601126200038457602063ffffffff60805416604051908152f35b5034620003845760c03660031901126200038457620003cb620033c7565b620003d56200340c565b90620003e06200343a565b906064359160ff8316809303620005c65760843560a435936001600160401b0394858111620005c2576200041990369060040162003666565b3360009081527fb3124b64d0942b276d75ea451f4dd8b83bf9442b427f9eb873ac771c92e65f02602052604090205490939060ff1615620005b057607e549663ffffffff6200046a818a16620036d3565b16809863ffffffff191617607e556040519060c0820190828210898311176200059a5789916040528a600160a01b6001900380991698898552806020860193169a8b84528060408701971696878152606087019289845280608089019580875260a08a01988d8a528152607f60205260409020985116906001600160601b0360a01b91828a541617895560018901965116908654161785555116620005109084620036ff565b519082549060ff60e81b9051151560e81b169160ff60e01b9060e01b169061ffff60e01b1916171790555190600201556040519586958652602086015260408501526060840152608083015260a0820160c0905260c082016200057391620036ac565b037fa2970448b3bd66ba7e524e7b2a5b9cf94fa29e32488fb942afdfe70dd4b77b5291a280f35b634e487b7160e01b600052604160045260246000fd5b604051637615be1f60e11b8152600490fd5b8780fd5b600080fd5b503462000384578060031936011262000384576040517f000000000000000000000000429a1ed765b18e78f068e98e5ab1212a21aa13146001600160a01b03168152602090f35b5034620003845760c0366003190112620003845762000630620033c7565b6200063a6200340c565b90620006456200343a565b606435906001600160401b03808316808403620005c65760a4359560ff871692838803620005c6573360009081527ff444741efd45fa05f38650e87f3d8ca01816575bed45a01e78186ae5f3bc8355602090815260409091205490989060ff1615620005b057838a526083895263ffffffff968760408c2054166200081157878511620007ff576001600160a01b03988916808c5260828b5260408c20549094908916620007ed5760805498620006fe818b16620036d3565b16988963ffffffff1980921617608055868d5260838c5260408d208a82825416179055898d8d888252608290526040902091825416179055888c5260818b5260408c20996001600160601b0360a01b9086828d5416178c5560018c0192620007678b85620036ff565b16908254161790556200077b9089620036ff565b60078801805460ff60801b191660809290921b60ff60801b1691909117905560405194168452868401526040830152606082015284608082015260a07fadfc7d56f7e39b08b321534f14bfb135ad27698f7d2f5ad0edc2356ea9a3f85091a28280526002019052608435604082205580f35b604051630d409b9360e41b8152600490fd5b604051634c753f5760e01b8152600490fd5b6040516337c8fe0960e11b8152600490fd5b503462000384576040366003190112620003845762000841620033c7565b6200084b6200347c565b6040516303e1469160e61b81529091906001600160a01b03808316919060208260048189875af19182156200096757869262000930575b50339116036200091e578352608260205263ffffffff8060408520541684526081602052604084206006810154906001600160401b039182808260401c169116036200090c576007015460401c169083161115620008fa57620008f79160405191620008ee83620035d0565b84835262003773565b80f35b604051633e37e23360e01b8152600490fd5b60405163664316a560e11b8152600490fd5b60405163696072e960e01b8152600490fd5b6200095791925060203d81116200095f575b6200094e8183620035ec565b81019062003752565b903862000882565b503d62000942565b6040513d88823e3d90fd5b5034620003845780600319360112620003845760206001600160401b0360845460401c16604051908152f35b503462000384578060031936011262000384573360009081527f307dd781c86f141a460373e0117a8033afea21c02f6121aff0f5b5553df24f4a602052604090205460ff1615620005b0576087805467ffffffffffffffff1916426001600160401b0316179055807f00000000000000000000000094a5c76eb7ab1ecd1ca43d637f9fc12b68a495d76001600160a01b0316803b1562000acf57818091600460405180948193636de0b4bb60e11b83525af1801562000ac45762000aac575b5050606f5460ff81161562000a9a5760ff1916606f557f1e5e34eea33501aecf2ebec9fe0e884a40804275ea7fe10b2ba084c8374308b38180a180f35b604051635386698160e01b8152600490fd5b62000ab79062003584565b6200038457803862000a5d565b6040513d84823e3d90fd5b50fd5b5034620003845780600319360112620003845760206001600160401b0360855416604051908152f35b5034620003845760403660031901126200038457620008f760043562000b206200340c565b90808452603460205262000b3b600160408620015462004aab565b62004ad0565b50346200038457602036600319011262000384573360009081527fe0205af17734f857fb538b40523c7cc189a1ab8f1ec33be516761c6b465766b660205260409020546004359060ff1615620005b057683635c9adc5dea000008111801562000bee575b62000bdc576020817ffb383653f53ee079978d0c9aff7aeff04a10166ce244cca9c9f9d8d96bed45b292608655604051908152a180f35b604051638586952560e01b8152600490fd5b50633b9aca00811062000ba5565b503462000384578060031936011262000384576040517f000000000000000000000000dbd32f81789bf2395d24d646a07a41639d9955fb6001600160a01b03168152602090f35b503462000384576020366003190112620003845760209063ffffffff906040906001600160a01b0362000c75620033c7565b16815260828452205416604051908152f35b503462000384576060366003190112620003845762000ca5620033c7565b62000caf6200347c565b6044356001600160401b03811162000d29573660238201121562000d295762000ce39036906024816004013591016200362a565b3360009081527ff14f5a8ad59d90593602e905b358229bff5ceea677d5bf0f5a1701793550a9a6602052604090205490919060ff1615620005b057620008f79262003773565b8380fd5b5034620003845780600319360112620003845760206001600160401b0360845460801c16604051908152f35b5034620003845760403660031901126200038457608090604062000d7c62003468565b9163ffffffff62000d8c62003423565b93826060855162000d9d81620035b4565b8281528260208201528287820152015216815260816020526004828220016001600160401b038094168252602052206040519062000ddb82620035b4565b8054928084169384845281602085019160401c16815260606002600185015494604087019586520154940193845260405194855251166020840152516040830152516060820152f35b50346200038457806003193601126200038457602061ffff60855460801c16604051908152f35b503462000384578060031936011262000384576040517f00000000000000000000000094a5c76eb7ab1ecd1ca43d637f9fc12b68a495d76001600160a01b03168152602090f35b50346200038457806003193601126200038457602062000eb162004528565b604051908152f35b50346200038457806003193601126200038457602090604051908152f35b503462000384576020366003190112620003845762000ef562003451565b62000eff62004a71565b6001600160401b0381169062015180821162000f6e57608580546fffffffffffffffff00000000000000001916604092831b67ffffffffffffffff60401b16179055519081527f1b023231a1ab6b5d93992f168fb44498e1a7e64cef58daff6f1c216de6a68c2890602090a180f35b604051631c0cfbfd60e31b8152600490fd5b503462000384576020366003190112620003845762000f9e62003451565b62000fa862004a71565b60ff606f54161562000ffe575b60206001600160401b037fc4121f4e22c69632ebb7cf1f462be0511dc034f999b52013eddfb24aab765c759216806001600160401b03196085541617608555604051908152a180f35b6001600160401b0380608554169082161062000fb55760405163048a05a960e41b8152600490fd5b50346200038457604036600319011262000384576200104462003451565b60ff606f54166200117f573382526020916082835263ffffffff6040822054169081156200116d576001600160401b03808416156200115b5762001124604083856200112a95526081885220916084549080620010a488828516620039bc565b16966001600160401b031997888094161760845560068501805483620010ce8183169485620039bc565b16998a911617905560405192620010e58462003598565b60243584528260018b8601958242168752604081019485528b600052600389018d5260406000209051815501945116908454161783555116906200372a565b62003f32565b7f1d9f30260051d51d70339da239ea7b080021adcaabfa71c9b0ea339a20cf9a2583604051848152a2604051908152f35b604051632590ccf960e01b8152600490fd5b6040516371653c1560e01b8152600490fd5b604051630bc011ff60e21b8152600490fd5b50346200038457806003193601126200038457602062000eb1620047d3565b50346200038457604036600319011262000384576040620011d06200340c565b9160043581526034602052209060018060a01b0316600052602052602060ff604060002054166040519015158152f35b50346200038457604036600319011262000384576200121e620033c7565b906200122962003423565b917f66156603fe29d13f97c6f3e3dff4ef71919f9aa61c555be0182d954e94221aac8252602090603482526040832033600052825260ff604060002054161580620014d3575b620014c15760018060a01b0316928383526082825263ffffffff604084205416918215620014af5782845260818152604084209160068301938454966001600160401b03958689168785169988828c10918215926200149f575b50506200148d57600387019688825b168b81146200132d57806000528888526001908a826040600020015460401c16908d82106200131b578b928d916000528b8b5260406000208281550155620012d8565b604051639753965f60e01b8152600490fd5b50620013538a9b9a9699939495996001600160401b0319938c8588541617875562003987565b9280620013666084549582871662003987565b16809385161780608455855491808360801c1662001427575b5050505050505085600052838352604060002054813b156200142357829160448392604051948593849263334d6f6760e11b84528c600485015260248401525af1801562000ac45762001407575b50507f80a6d395a55aed8126079cb8247f0a6848b1440ca2cdca3b4386f250c352940291846000528152604060002054604051908152a380f35b620014129062003584565b6200141f578438620013cd565b8480fd5b8280fd5b620014546200145f93826200144867ffffffffffffffff60401b9762004761565b9160401c169062003987565b9160401c1662003987565b60401b16916001600160801b03191617176084556001600160801b038154169055388080808080806200137f565b60405163cb23ebdf60e01b8152600490fd5b60401c168b1090508838620012c9565b6040516374a086a360e01b8152600490fd5b604051630d03687f60e11b8152600490fd5b506040516303e1469160e61b81526001600160a01b038382600481888786165af1918215620015335785926200150f575b50163314156200126f565b6200152b919250843d86116200095f576200094e8183620035ec565b903862001504565b6040513d87823e3d90fd5b50346200038457620015503662003490565b969592919360ff606f96929654166200117f577f1f44c21118c4603cfb4e1b621dbcfa2b73efcececee2b99b620b2953d33a701097866004966001600160401b0395620015b3948660408f63ffffffff829f168152608160205220998a62004179565b16865201602052600282852001549082519182526020820152a1620008f7620043f4565b50346200038457620015e93662003506565b9060ff606f9897989693959654166200117f5763ffffffff87168952608160205260408920976001600160401b03871660005260038901602052620016466001600160401b036001604060002001541660845460c01c90620039bc565b6001600160401b034291161162001a96576103e86001600160401b036200166e868a62003987565b161162001a84578487620016859588938c62003a2e565b620016908562004761565b94839587906001600160401b03620016a9828862003987565b169060855492620016c76001600160401b038560401c1642620043c5565b995b6001600160401b0383166001600160401b0382161462001a6e576001600160401b03811660005260038601602052600160406000200154906001600160401b0382168c1060001462001728575060401c6001600160401b0316620016c9565b620017559495969798999a9b506200174c92506001600160401b0393915062003987565b168092620043c5565b918183101562001a12575003600c81111562001a0757506200178f600c5b6086548161ffff60855460801c160a02906103e80a90620043d3565b6086555b608654683635c9adc5dea000009081811115620019e657506086555b6085546001600160401b0316620018f3578160056006830192620017d487856200372a565b6001600160401b0387166000526002810160205285604060002055015580546001600160401b038160801c16620018e0575b508590507f000000000000000000000000dbd32f81789bf2395d24d646a07a41639d9955fb6001600160a01b03166200183e62004528565b813b15620014235782916024839260405194859384926333d6247d60e01b845260048401525af1801562000ac457620018c8575b50507faac1e7a157b259544ebacd6e8a82ae5d6c8f174e12aa48696277bcc9a661f0b4915b604080516001600160401b0390951685526020850191909152830152339263ffffffff169180606081015b0390a380f35b620018d39062003584565b6200141f57843862001872565b6001600160801b03169055388062001806565b620019018193929362003f32565b6006810180546001600160401b038160801c166001600160401b038114620019d2579385620019c26001600160401b03898160408e6004889b847faac1e7a157b259544ebacd6e8a82ae5d6c8f174e12aa48696277bcc9a661f0b49f9e9c60029c60609e60018460801b910160801b16908360801b19161780915585519d8e6200198b81620035b4565b834216815283602082019a168a528781019c8d52019b8c5260801c168352016020522097511682198854161787555116856200372a565b5160018401555191015562001897565b634e487b7160e01b89526011600452602489fd5b9050633b9aca00809110620019fd575b50620017af565b60865538620019f6565b6200178f9062001773565b9062001a599203600c811160001462001a62575062001a4e600c915b670de0b6b3a76400009261ffff816103e80a9260801c160a8302620043d3565b9060865402620043d3565b60865562001793565b62001a4e909162001a2e565b50929394959697985050816200175591620043c5565b604051635acfba9d60e11b8152600490fd5b604051638a0704d360e01b8152600490fd5b50346200038457806003193601126200038457602060845460c01c604051908152f35b503462000384576020366003190112620003845763ffffffff60406020926001600160401b0362001afb62003451565b16815260838452205416604051908152f35b5034620003845760c0366003190112620003845762001b6d62001b829162001b3462003468565b9062001b3f62003423565b9063ffffffff62001b4f6200343a565b93168152608160205260a4359260843592604060643593206200489f565b604051918291602083526020830190620036ac565b0390f35b5034620003845760e0366003190112620003845762001ba462003468565b9062001baf62003423565b60443592906001600160a01b0384168403620005c65762001bcf620033de565b9062001bda620033f5565b9060a4356001600160401b03811162001fc05762001bfd90369060040162003666565b9260c4356001600160401b03811162001fbc5762001c2090369060040162003666565b3360009081527f41902c3bd358ff4b85ee46864bd81ee453a1b3cfd703a58950be8d28ae030661602052604090205460ff1615620005b05763ffffffff861615801562001fa4575b62001f925763ffffffff86168752607f6020526040872097600160ff818b015460e81c1615151462001f805763ffffffff6001600160401b03851611620007ff576001600160401b0384168852608360205263ffffffff60408920541662000811576080549463ffffffff62001ce0818816620036d3565b1663ffffffff1996909616861760805589546040519a906001600160a01b031662001d0b8c620035d0565b8a8c52604051908161061f8101106001600160401b0361061f8401111762001f6c5762001d5d8c9d839261061f62004b48853961061f84019081523060208201526060604082018190520190620036ac565b03908bf095861562001f615787926001600160401b038262001e828d8f60017f194c983456df6701c6a50830b90fe80e72b823411d0d524970c9590dc277a6419862001e5f8f600763ffffffff9160ff968f8c60809f168252608360205260408220818619825416179055878060a01b03831682526082602052604082208186198254161790558152608160205260408120916001600160601b0360a01b90888060a01b0316818454161783558c8888015460a01c169062001e238985019283620036ff565b888060a01b0389890154169082541617905562001e418b83620036ff565b6040600287015491808052600284016020522055019516856200372a565b0154825460ff60801b191660e09190911c9190911660801b60ff60801b16179055565b63ffffffff6040519d168d528c602060018060a01b038c169101521660408c015260018060a01b0316998a6060820152a26001600160a01b0384163b15620005c257604051633892b81160e11b81526001600160a01b039182166004820152921660248301526044820193909352606481019490945260c060848501528492849283918591839162001f32919062001f1f9060c4850190620036ac565b8381036003190160a485015290620036ac565b03926001600160a01b03165af1801562000ac45762001f4e5750f35b62001f599062003584565b620003845780f35b6040513d8c823e3d90fd5b634e487b7160e01b8c52604160045260248cfd5b604051633b8d3d9960e01b8152600490fd5b604051637512e5cb60e01b8152600490fd5b5063ffffffff607e541663ffffffff87161162001c68565b8680fd5b8580fd5b503462000384576020366003190112620003845762001fe262003468565b3360009081527fd26c1f3d72948c9f5ca2b28d010847694e18f81d42613c046515d0839b64354c602052604090205460ff1615620005b05763ffffffff8091169081159081156200208c575b5062001f9257808252607f602052600160408320018054600160ff8260e81c1615151462001f805760ff60e81b1916600160e81b1790557f4710d2ee567ef1ed6eb2f651dde4589524bcf7cebc62147a99b281cc836e7e448280a280f35b9050607e54168111386200202e565b5034620003845760203660031901126200038457604060c09163ffffffff620020c362003468565b168152607f6020522060018060a01b0360ff81835416926002600182015491015492604051948552811660208501526001600160401b038160a01c166040850152818160e01c16606085015260e81c161515608083015260a0820152f35b50346200038457806003193601126200038457608654906064820291808304606414901517156200215757602082604051908152f35b634e487b7160e01b81526011600452602490fd5b50346200038457604036600319011262000384576001600160401b03600260406200219562003468565b9363ffffffff620021a562003423565b951681526081602052200191166000526020526020604060002054604051908152f35b503462000384578060031936011262000384576020608654604051908152f35b50346200038457602036600319011262000384576200220662003451565b6200221062004a71565b60ff606f54161562002275575b608480546001600160c01b031660c083901b6001600160c01b0319161790556040516001600160401b0390911681527f1f4fa24c2e4bad19a7f3ec5c5485f70d46c798461c2e684f55bbd0fc661373a190602090a180f35b60845460c01c6001600160401b038216106200221d5760405163401636df60e01b8152600490fd5b5034620003845760403660031901126200038457620022bb6200340c565b336001600160a01b03821603620022da57620008f79060043562004ad0565b604051630b4ad1cd60e31b8152600490fd5b5034620003845780600319360112620003845760206001600160401b0360875416604051908152f35b5034620003845760403660031901126200038457600435620023366200340c565b818352603460205262002350600160408520015462004aab565b8183526034602052604083209060018060a01b0316908160005260205260ff604060002054161562002380578280f35b818352603460205260408320816000526020526040600020600160ff198254161790553391600080516020620051678339815191528480a438808280f35b503462000384576040366003190112620003845760609060036040620023e362003468565b9263ffffffff620023f362003423565b9482848051620024038162003598565b8281528260208201520152168152608160205220016001600160401b038092166000526020526040600020906040516200243d8162003598565b81600184549485845201549181604060208301928286168452019360401c1683526040519485525116602084015251166040820152f35b503462000384576020366003190112620003845760016040602092600435815260348452200154604051908152f35b503462000384578060031936011262000384577f141f8f32ce6198eee741f695cec728bfd32d289f1acf73621fb303581000545e81526034602052604081203360005260205260ff604060002054161562002503575b620008f7620043f4565b6001600160401b038060845460801c169081159182156200255d575b50811562002541575b5015620024f95760405163692baaad60e11b8152600490fd5b9050620025528160875416620039a1565b429116113862002528565b6200256a919250620039a1565b814291161190386200251f565b503462000384576020366003190112620003845760043561ffff8116908181036200142357620025a662004a71565b6103e88210801562002618575b62002606576085805461ffff60801b191660809290921b61ffff60801b169190911790556040519081527f7019933d795eba185c180209e8ae8bffbaa25bcef293364687702c31f4d302c590602090a180f35b604051630984a67960e31b8152600490fd5b506103ff8211620025b3565b50346200038457806003193601126200038457602063ffffffff607e5416604051908152f35b50346200038457604036600319011262000384576200266862003468565b63ffffffff6200267762003423565b91168252608160205260408220907f084e94f375e9d647f87f5b2ceffba1e062c70f6009fdbcf80291e803b5c9edd483526034602052604083203360005260205260ff6040600020541615620026d3575b620008f79162003fdc565b60ff606f54166200117f57620026ea81836200479e565b620026c857604051630674f25160e11b8152600490fd5b50346200038457806003193601126200038457602060ff606f54166040519015158152f35b503462000384576200276f63ffffffff620027413662003506565b9284819796998499620027599c979c95949562004a37565b16998a8d52608160205260408d20978862003a2e565b60068101906200278086836200372a565b8260056001600160401b0392838916600052600281016020528660406000205501558154908160801c1662002882575b508590507f000000000000000000000000dbd32f81789bf2395d24d646a07a41639d9955fb6001600160a01b0316620027e862004528565b813b15620014235782916024839260405194859384926333d6247d60e01b845260048401525af1801562000ac4576200286a575b5050604080516001600160401b03909516855260208501929092529083015233917fd1ec3a1216f08b6eff72e169ceb548b782db18a6614852618d86bb19f3f9b0d3908060608101620018c2565b620028759062003584565b6200141f5784386200281c565b6001600160801b031690553880620027b0565b50346200038457620028dd63ffffffff620028b03662003490565b92809599948297998499620028c795949562004a37565b169a8b8d52608160205260408d209a8b62004179565b6006840190620028ee81836200372a565b8360056001600160401b0380931696878a52600281016020528560408b205501558154908160801c1662002a1d575b508590507f000000000000000000000000dbd32f81789bf2395d24d646a07a41639d9955fb6001600160a01b03166200295562004528565b90803b1562001423576024839260405194859384926333d6247d60e01b845260048401525af180156200096757620029e0575b50608480546001600160c01b031661127560c71b1790556040805193845260208401919091528201523360608201527f3182bd6e6f74fc1fdc88b60f3a4f4c7f79db6ae6f5b88a1b3f5a1e28ec210d5e90608090a280f35b917f3182bd6e6f74fc1fdc88b60f3a4f4c7f79db6ae6f5b88a1b3f5a1e28ec210d5e93919562002a1260809462003584565b959193509162002988565b6001600160801b0316905538806200291d565b503462000384576020366003190112620003845762002a6a604060209263ffffffff62002a5c62003468565b168152608184522062004761565b6001600160401b0360405191168152f35b5034620003845780600319360112620003845760206001600160401b0360855460401c16604051908152f35b503462000384576040366003190112620003845762002aed602091604062002ace62003468565b9163ffffffff62002ade62003423565b9316815260818552206200479e565b6040519015158152f35b5034620003845780600319360112620003845760206001600160401b0360845416604051908152f35b905034620033c357610140366003190112620033c35762002b40620033c7565b62002b4a62003423565b62002b546200343a565b62002b5e620033de565b62002b68620033f5565b6001600160a01b039360a435858116949190859003620033bf5760c43586811603620033bf5760e43586811603620033bf576001600160401b03906101043582811603620033bb576101243582811603620033bb57895460ff998a8260081c161580620033ae575b1562003355575061ffff191661010217808b5560858054608480546001600160c01b031660c09790971b6001600160c01b0319169690961790955567016345785d8a00006086556fffffffffffffffffffffffffffffffff19909416929091169190911769070800000000000000001761ffff60801b19166101f560811b1790915560081c861615620032fc577f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498957f084e94f375e9d647f87f5b2ceffba1e062c70f6009fdbcf80291e803b5c9edd4948589526034926020978489528260408c20911690818c5289528360408c20541615620032c2575b508980528388528160408b20911690818b5288528260408b2054161562003289575b7fac75d24dbb35ea80e25fab167da4dea46c1915260426570db84f184891f5f590808b5284895260408b20828c5289528360408c205416156200324e575b507f3dfe277d2a2c04b75fb2eb3743fa00005ae3678a20c299e65fdf4df76517f68e808b5284895260408b20828c5289528360408c2054161562003213575b507f66156603fe29d13f97c6f3e3dff4ef71919f9aa61c555be0182d954e94221aac90818b5284895260408b20818c5289528360408c20541615620031d9575b50507fab66e11c4f712cd06ab11bf9339b48bef39e12d4a22eeef71d2860a0c90482bd90818a5283885260408a20941693848a5287528160408a205416156200319e575b507fa0fab074aba36a6fa69f1a83ee86e5abfb8433966eb57efb13dc2fc2f24ddd0880895282875260408920848a5287528160408a2054161562003163575b507f62ba6ba2ffed8cfe316b583325ea41ac6e7ba9e5864d2bc6fabba7ac26d2f0f480895282875260408920848a5287528160408a2054161562003128575b507fa5c5790f581d443ed43873ab47cfb8c5d66a6db268e58b5971bb33fc66e07db180895282875260408920848a5287528160408a20541615620030ed575b508488528186526001928360408a20018054907f73cb0569fdbea2544dae03fdb2fe10eda92a72a2e8cd2bd496e85b762505a3f091828092557fbd79b86ffe0ab8e8776151514217cd7cacd52c909f66475c3af44e129f0b00ff98898d80a4808a5260408a20828b5288528260408b20541615620030b3575b507f8cf807f6970720f8e2c208c7c5037595982c7bd9ed93c380d09df743d0dcc3fb90818a5283885260408a20818b5288528260408b205416156200307a575b50507f141f8f32ce6198eee741f695cec728bfd32d289f1acf73621fb303581000545e808952828752604089208481018054837f9b6f082d8d3644ae2f24a3c32e356d6f2d9b2844d9b26164fbc82663ff285951998a8094558d80a4858a5287528160408a2054161562003040575b508488528186526040882084895286526040882054161562003005575b5050845461ff0019168555505060405160028152a180f35b8387528452604086208287528452604086209060ff198254161790553391600080516020620051678339815191528680a43880808062002fed565b80895282875260408920858a528752604089208460ff19825416179055843391600080516020620051678339815191528b80a43862002fd0565b818a528388526040808b20828c5289528a20805460ff1916861790553391600080516020620051678339815191528b80a4388062002f61565b808a5283885260408a20828b52885260408a208560ff19825416179055813391600080516020620051678339815191528c80a43862002f21565b80895282875260408920848a52875260408920600160ff19825416179055833391600080516020620051678339815191528b80a43862002ea8565b80895282875260408920848a52875260408920600160ff19825416179055833391600080516020620051678339815191528b80a43862002e69565b80895282875260408920848a52875260408920600160ff19825416179055833391600080516020620051678339815191528b80a43862002e2a565b80895282875260408920848a52875260408920600160ff19825416179055833391600080516020620051678339815191528b80a43862002deb565b818b528489526040808c20828d528a528b20805460ff191660011790553391600080516020620051678339815191528c80a4388062002da7565b808b5284895260408b20828c52895260408b20600160ff19825416179055813391600080516020620051678339815191528d80a43862002d67565b808b5284895260408b20828c52895260408b20600160ff19825416179055813391600080516020620051678339815191528d80a43862002d28565b8980528388526040808b20828c5289528a20805460ff1916600117905533818b600080516020620051678339815191528180a462002cea565b878b528489526040808c20828d528a528b20805460ff19166001179055339088600080516020620051678339815191528d80a43862002cc8565b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b62461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b5060028b83161062002bd0565b8980fd5b8880fd5b5080fd5b600435906001600160a01b0382168203620005c657565b606435906001600160a01b0382168203620005c657565b608435906001600160a01b0382168203620005c657565b602435906001600160a01b0382168203620005c657565b602435906001600160401b0382168203620005c657565b604435906001600160401b0382168203620005c657565b600435906001600160401b0382168203620005c657565b6004359063ffffffff82168203620005c657565b6024359063ffffffff82168203620005c657565b6103e0600319820112620005c65760043563ffffffff81168103620005c657916001600160401b036024358181168103620005c657926044358281168103620005c657926064358381168103620005c657926084359081168103620005c6579160a4359160c435916103e411620005c65760e490565b6103e0600319820112620005c65760043563ffffffff81168103620005c657916001600160401b03906024358281168103620005c657926044358381168103620005c657926064359081168103620005c657916084359160a4359160c4356001600160a01b0381168103620005c657916103e411620005c65760e490565b6001600160401b0381116200059a57604052565b606081019081106001600160401b038211176200059a57604052565b608081019081106001600160401b038211176200059a57604052565b602081019081106001600160401b038211176200059a57604052565b90601f801991011681019081106001600160401b038211176200059a57604052565b6001600160401b0381116200059a57601f01601f191660200190565b92919262003638826200360e565b91620036486040519384620035ec565b829481845281830111620005c6578281602093846000960137010152565b9080601f83011215620005c65781602062003684933591016200362a565b90565b60005b8381106200369b5750506000910152565b81810151838201526020016200368a565b90602091620036c78151809281855285808601910162003687565b601f01601f1916010190565b63ffffffff809116908114620036e95760010190565b634e487b7160e01b600052601160045260246000fd5b805467ffffffffffffffff60a01b191660a09290921b67ffffffffffffffff60a01b16919091179055565b9067ffffffffffffffff60401b82549160401b169067ffffffffffffffff60401b1916179055565b90816020910312620005c657516001600160a01b0381168103620005c65790565b92919063ffffffff8091168015801562003979575b62001f925760018060a01b038095169460009580875260826020526040938488205416948515620039685785885260816020528488209260078401938454906001600160401b03908782848b1c16146200395757878c52607f602052888c209260018401805491600160ff8460e81c16151514620039465760ff808460e01c169160801c1603620039355782918462003841928860016006970193166001600160601b0360a01b8454161783555460a01c1690620036ff565b6200384d89896200372a565b0154818160c01c9160801c16036200392457908a93929189855260816020526200387989862062004761565b1695866001600160401b0319825416179055541692803b156200142357620038c49383885180968195829463278f794360e11b845260048401528b60248401526044830190620036ac565b03925af180156200391a577ff585e04c05d396901170247783d3e5f0ee9c1df23072985b50af089f5e48b19d9596975062003908575b5082519182526020820152a2565b620039139062003584565b38620038fa565b84513d89823e3d90fd5b8751639d59507b60e01b8152600490fd5b8a51635aa0d5f160e11b8152600490fd5b8b51633b8d3d9960e01b8152600490fd5b8851634f61d51960e01b8152600490fd5b84516374a086a360e01b8152600490fd5b5081607e5416811162003788565b6001600160401b039182169082160391908211620036e957565b9062093a806001600160401b0380931601918211620036e957565b9190916001600160401b0380809416911601918211620036e957565b90816020910312620005c657518015158103620005c65790565b9291906103208401936103008092823701906000915b6001831062003a1657505050565b60019082518152602080910192019201919062003a08565b9295909496939160009262003a438562004761565b916001600160401b03948560078801541698868316998a1062003e7d57861690811562003e37575085600688015460801c16811162003e2557600052600486016020526040600020978560028a0154995460401c160362003e13575b8489169785841689111562003e015762003abd928a8c93896200489f565b9060409788519260008480835162003adc816020998a80980162003687565b8101039060025afa1562003df65760005160018701548a516001600160a01b039962003b549387938c1691907f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001900662003b3684620035d0565b83528d51809581948293634890ed4560e11b845260048401620039f2565b03915afa90811562003deb5760009162003db7575b501562003da6579062003b7c9162003987565b9162003b87620047d3565b84841690818102918183041490151715620036e957885190878483019363a9059cbb60e01b855216602483015260448201526044815262003bc881620035b4565b867f000000000000000000000000429a1ed765b18e78f068e98e5ab1212a21aa1314168951918a8301838110888211176200059a578b528483527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564838601525162003c6893600091829182855af13d1562003d9d573d9162003c4a836200360e565b9262003c598d519485620035ec565b83523d60008785013e62003e8f565b80518062003d26575b50505062003c9367ffffffffffffffff60401b916084549384891c16620039bc565b77ffffffffffffffffffffffffffffffff00000000000000001990921691861b16174260801b67ffffffffffffffff60801b1617608455541692833b15620005c657606460009283855196879485936332c2d15360e01b8552600485015260248401523360448401525af190811562003d1c575062003d0f5750565b62003d1a9062003584565b565b513d6000823e3d90fd5b90828062003d39938301019101620039d8565b1562003d4757808062003c71565b60849087519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b60609162003e8f565b88516309bde33960e01b8152600490fd5b62003ddc9150843d861162003de3575b62003dd38183620035ec565b810190620039d8565b3862003b69565b503d62003dc7565b8a513d6000823e3d90fd5b88513d6000823e3d90fd5b60405163b9b18f5760e01b8152600490fd5b604051632bd2e3e760e01b8152600490fd5b60405163bb14c20560e01b8152600490fd5b6040915089815260028801602052205497881562003e6b57858416101562003a9f57604051630f2b74f160e11b8152600490fd5b6040516324cbdcc360e11b8152600490fd5b60405163ead1340b60e01b8152600490fd5b9192901562003ef4575081511562003ea5575090565b3b1562003eaf5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b82519091501562003f085750805190602001fd5b60405162461bcd60e51b81526020600482015290819062003f2e906024830190620036ac565b0390fd5b60068101546001600160401b0390818160801c169060c01c80821162003f59575b50505050565b600101918211620036e95762003f7082846200479e565b62003f7d575b8062003f53565b677fffffffffffffff62003f968362003fa19362003987565b60011c1682620039bc565b9062003fae82846200479e565b1562003fc9575062003fc09162003fdc565b38808062003f76565b905062003fd69162003fdc565b62003fc0565b9060068201908154906000936001600160401b039485831693868160c01c86119182159262004169575b5050620041575783815260048201602052604091828220968754841c16956200403087826200372a565b60028881018054898652918401602052858520919091556001989098018054600584015581546001600160c01b031660c09690961b6001600160c01b0319169590951790556001600160a01b03907f000000000000000000000000dbd32f81789bf2395d24d646a07a41639d9955fb8216620040ab62004528565b813b156200141f57849160248392885194859384926333d6247d60e01b845260048401525af180156200414d5793859363ffffffff9360809997937f581910eb7a27738945c2f00a91f2284b2d6de9d4e472b12f901c2b0df045e21b9b999762004137575b505416815260826020522054169654915491815194855260208501528301526060820152a2565b620041459093919362003584565b913862004110565b85513d86823e3d90fd5b60405163d086b70b60e01b8152600490fd5b60801c1685119050863862004006565b9192939496906000976001600160401b039889600786015416928a881693841062003e7d578a169081156200438b575089600686015460801c16811162003e255780600052600485016020526040600020928a6002850154945460401c160362003e13575b8960068601549616958a8160801c1687119182156200437f575b50811562004370575b506200435e5760048401968560005260209688885260409a808c600020548d1c16908316036200434d57898894600094620042559462004242948a6200489f565b838b519282848094519384920162003687565b8101039060025afa1562004342576000516001909201548751620042ce93869391926001600160a01b031691907f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000019006620042b084620035d0565b83528951809581948293634890ed4560e11b845260048401620039f2565b03915afa908115620043425760009162004320575b50156200430f5760005252600282600020015414620042ff5750565b5163a47276bd60e01b8152600490fd5b84516309bde33960e01b8152600490fd5b6200433b9150833d851162003de35762003dd38183620035ec565b38620042e3565b86513d6000823e3d90fd5b8a516332a2a77f60e01b8152600490fd5b60405163bfa7079f60e01b8152600490fd5b905060c01c8511153862004201565b871115915038620041f8565b80846040925260028701602052205492831562003e6b578a600687015460401c161015620041de57604051630f2b74f160e11b8152600490fd5b91908203918211620036e957565b8115620043de570490565b634e487b7160e01b600052601260045260246000fd5b7f00000000000000000000000094a5c76eb7ab1ecd1ca43d637f9fc12b68a495d76001600160a01b0316803b15620005c6576040518091632072f6c560e01b82528160046000948580945af1801562000ac4576200448b575b50606f549060ff82166200117f5760017f2261efe5aef6fedc1fd1550b25facc9181745623049c7901287030b9ad1a54979260ff191617606f5580a1565b620044969062003584565b386200444d565b6001600160401b0381116200059a5760051b60200190565b90620044c1826200449d565b620044d06040519182620035ec565b8281528092620044e3601f19916200449d565b0190602036910137565b6000198114620036e95760010190565b8051821015620045125760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b63ffffffff806080541680156200475a576200454481620044b5565b9160005b828110620047235750509060006020915b600190818514620046ab578185811c951691828601809611620036e9576200458186620044b5565b9160009160001994858901898111945b8a8110620045d457505050505050939160408051906020820192808452818301528152620045bf8162003598565b519020928015620036e9570191909262004559565b85620036e95781811480620046a1575b15620046485780841b9080820460021481151715620036e9576200460d620046429287620044fd565b516040805190602082019283528c8183015281526200462c8162003598565b5190206200463b828a620044fd565b52620044ed565b62004591565b80841b9080820460021481151715620036e957620046678287620044fd565b51858301809311620036e95762004683620046429388620044fd565b516040805191602083019384528183015281526200462c8162003598565b50838314620045e4565b91935050805115620045125760200151916000905b828210620046ce5750505090565b6200471c906040948551602081019182528287820152868152620046f28162003598565b519020948051906020820192808452818301528152620047128162003598565b51902091620044ed565b90620046c0565b6001810190818111620036e9578262004754921660005260816020526005604060002001546200463b8287620044fd565b62004548565b5050600090565b60068101546001600160401b0391608082901c831680156200479557600492506000520160205260406000205460401c1690565b505060401c1690565b6004906001600160401b0380931660005201602052620047cb8160406000205416826085541690620039bc565b429116111590565b6040516370a0823160e01b81523060048201526020816024817f000000000000000000000000429a1ed765b18e78f068e98e5ab1212a21aa13146001600160a01b03165afa90811562004893576000916200485c575b50608454620048496001600160401b039182808260401c16911662003987565b1680156200475a576200368491620043d3565b906020823d82116200488a575b816200487860209383620035ec565b81010312620003845750513862004829565b3d915062004869565b6040513d6000823e3d90fd5b92939094916001600160401b039485871660009481865260038701602052604096878720549989861688528888205493151580620049bd575b620049ac5783156200499b57620048ef83620049c6565b156200498a579060749160018254920154918a519c8d993360601b60208c015260348b015260548a01526001600160401b0360c01b98899485809460c01b1691015260201b16607c8c015260201b1660848a0152608c89015260ac88015260cc87015260c01b1660ec85015260d48452610100840192848410908411176200497657505290565b634e487b7160e01b81526041600452602490fd5b88516305dae44f60e21b8152600490fd5b88516366385b5160e01b8152600490fd5b885163340c614f60e11b8152600490fd5b508a15620048d8565b67ffffffff000000016001600160401b03918183821610928362004a26575b8362004a14575b508262004a06575b50501562004a0157600190565b600090565b60c01c1090503880620049f4565b818392945060801c16109138620049ec565b925081838260401c161092620049e5565b3360009081527fc17b14a573f65366cdad721c7c0a0f76536bb4a86b935cdac44610e4f010b52a602052604090205460ff1615620005b057565b3360009081527f3b72b60ab7bcf7b6e5f79e30b28eb2a39d66a2a278905c2bfcfdd4e1c0a1907b602052604090205460ff1615620005b057565b600052603460205260406000203360005260205260ff6040600020541615620005b057565b906000918083526034602052604083209160018060a01b03169182845260205260ff60408420541662004b0257505050565b8083526034602052604083208284526020526040832060ff1981541690557ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b339380a456fe604060a0815261061f803803806100158161023b565b92833981016060828203126102365761002d82610276565b9060209161003c838501610276565b8585015190946001600160401b038211610236570182601f820112156102365780519061007061006b8361028a565b61023b565b9382855285838301011161023657849060005b83811061022257505060009184010152803b15610201577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b03199081166001600160a01b038481169182179093558751929691948794929390917fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a28151156101e0575090600080838861014695519101845af43d156101d8573d9161013761006b8461028a565b9283523d60008985013e6102a5565b505b8060805216917f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f857fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103958587549483519286168352820152a182156101c05716179055516103169081610309823960805181600f0152f35b8451633173bdd160e11b815260006004820152602490fd5b6060916102a5565b9293505050346101f257508390610148565b63b398979f60e01b8152600490fd5b8451634c9c8ce360e01b81526001600160a01b039091166004820152602490fd5b818101830151868201840152869201610083565b600080fd5b6040519190601f01601f191682016001600160401b0381118382101761026057604052565b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b038216820361023657565b6001600160401b03811161026057601f01601f191660200190565b906102cc57508051156102ba57805190602001fd5b604051630a12f52160e11b8152600490fd5b815115806102ff575b6102dd575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156102d556fe60806040526001600160a01b03337f00000000000000000000000000000000000000000000000000000000000000008216036100e05760009081356001600160e01b03191663278f794360e11b141582036100e057366004116100dc5760403660031901126100dc576004359081168091036100dc576024359067ffffffffffffffff82116100d857366023830112156100d85781600401356100a96100a48261016d565b610142565b9281845236602483830101116100d457816100d295926024602093018387013784010152610189565b005b8480fd5b8280fd5b5080fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc54600090819081906001600160a01b0316368280378136915af43d82803e15610128573d90f35b3d90fd5b634e487b7160e01b600052604160045260246000fd5b6040519190601f01601f1916820167ffffffffffffffff81118382101761016857604052565b61012c565b67ffffffffffffffff811161016857601f01601f191660200190565b90813b15610221577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a28051156102065761020391610242565b50565b50503461020f57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b60008061027693602081519101845af43d15610279573d916102666100a48461016d565b9283523d6000602085013e61027d565b90565b6060915b906102a4575080511561029257805190602001fd5b604051630a12f52160e11b8152600490fd5b815115806102d7575b6102b5575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156102ad56fea2646970667358221220ddf15a6f4a4e94f45015fba958b16bfe0063f6be348dd5f915b909c5caee6cd064736f6c634300081400332f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0da264697066735822122037397a8e35cbdd5aefd144980560c0cefa434b2ab29a1d16fa4adfa2aac653a864736f6c63430008140033