Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
There are no matching entriesUpdate your filters to view other transactions | |||||||||
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
AggchainECDSAMultisig
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 999999 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.28;
import "../lib/AggchainBase.sol";
/**
* @title AggchainECDSAMultisig
* @notice Generic aggchain based on ECDSA multisig signature.
* An array of addresses signs the new_ler and the commit_imported_bridge_exits in order to do state
* transitions on the pessimistic trees (local_exit_tree, local_balance_tree, nullifier_tree & height).
* The addresses and threshold are managed by the aggchainManager.
*/
contract AggchainECDSAMultisig is AggchainBase {
////////////////////////////////////////////////////////////
// Transient Storage //
////////////////////////////////////////////////////////////
uint8 private transient _initializerVersion;
////////////////////////////////////////////////////////////
// Constants & Immutables //
////////////////////////////////////////////////////////////
// Aggchain type selector, hardcoded value used to force the last 2 bytes of aggchain selector to retrieve the aggchain verification key
bytes2 public constant AGGCHAIN_TYPE = 0x0000;
/// @notice Aggchain version
string public constant AGGCHAIN_ECDSA_MULTISIG_VERSION = "v1.0.0";
////////////////////////////////////////////////////////////
// Errors //
////////////////////////////////////////////////////////////
/// @notice Thrown when trying to initialize the wrong initialize function.
error InvalidInitializer();
/// @notice Thrown when calling a function that is not supported by this implementation.
error FunctionNotSupported();
////////////////////////////////////////////////////////////
// Events //
////////////////////////////////////////////////////////////
/// @notice Emitted when pessimistic verification is completed.
event OnVerifyPessimisticECDSAMultisig();
////////////////////////////////////////////////////////////
// Modifiers //
////////////////////////////////////////////////////////////
/// @dev Modifier to retrieve initializer version value previous on using the reinitializer modifier, its used in the initialize function.
modifier getInitializedVersion() {
// Get initializer version from OZ initializer smart contract
_initializerVersion = _getInitializedVersion();
_;
}
////////////////////////////////////////////////////////////
// Constructor //
////////////////////////////////////////////////////////////
/**
* @param _globalExitRootManager Global exit root manager address.
* @param _pol POL token contract address.
* @param _bridgeAddress Bridge contract address.
* @param _rollupManager Rollup manager contract address.
* @param _aggLayerGateway AgglayerGateway contract address.
*/
constructor(
IAgglayerGER _globalExitRootManager,
IERC20Upgradeable _pol,
IAgglayerBridge _bridgeAddress,
AgglayerManager _rollupManager,
IAgglayerGateway _aggLayerGateway
)
AggchainBase(
_globalExitRootManager,
_pol,
_bridgeAddress,
_rollupManager,
_aggLayerGateway
)
{}
////////////////////////////////////////////////////////////
// Functions: initialization //
////////////////////////////////////////////////////////////
/**
* @notice Initialize the AggchainECDSAMultisig contract
* @param _admin Admin address
* @param _trustedSequencer Trusted sequencer address
* @param _gasTokenAddress Gas token address
* @param _trustedSequencerURL Trusted sequencer URL
* @param _networkName Network name
* @param _useDefaultSigners Whether to use default signers from gateway
* @param _signersToAdd Array of signers to add
* @param _newThreshold New threshold for multisig operations
* @custom:security First initialization takes into account this contracts and all the inheritance contracts
* This function can only be called when the contract is first deployed (version 0)
* @dev The reinitializer(2) is set to support the upgrade from PolygonPessimisticConsensus to AggchainECDSAMultisig, where PolygonPessimisticConsensus is already initialized
*/
function initialize(
address _admin,
address _trustedSequencer,
address _gasTokenAddress,
string memory _trustedSequencerURL,
string memory _networkName,
bool _useDefaultSigners,
SignerInfo[] memory _signersToAdd,
uint256 _newThreshold
) external onlyAggchainManager getInitializedVersion reinitializer(2) {
if (_initializerVersion != 0) {
revert InvalidInitializer();
}
// initOwnedAggchainVKey, initAggchainVKeySelector, and useDefaultVkeys are not used in this aggchain.
_initializeAggchainBaseAndConsensusBase(
_admin,
_trustedSequencer,
_gasTokenAddress,
_trustedSequencerURL,
_networkName,
false, // useDefaultVkeys
_useDefaultSigners,
bytes32(0), // initOwnedAggchainVKey
bytes4(0) // initAggchainVKeySelector
);
// Check the used default signers is consistent
if (_useDefaultSigners) {
if (_signersToAdd.length != 0 || threshold != 0) {
revert ConflictingDefaultSignersConfiguration();
}
} else {
// update signers and threshold
_updateSignersAndThreshold(
new RemoveSignerInfo[](0), // No signers to remove
_signersToAdd,
_newThreshold
);
}
}
/**
* @notice Migrates from PolygonPessimisticConsensus or PolygonRollupBaseEtrog to AggchainECDSAMultisig
* @dev This function is called when upgrading from a PolygonPessimisticConsensus contract.
* - Therefore the consensusBase is already initialized.
* - The AggchainBase is initialized using the values from the ConsensusBase.
* It sets up the initial multisig configuration using the existing admin and trustedSequencer,
* Sets the threshold to 1, and adds the trustedSequencer as the only signer.
*/
function migrateFromLegacyConsensus()
external
onlyRollupManager
getInitializedVersion
reinitializer(2)
{
if (_initializerVersion != 1) {
revert InvalidInitializer();
}
// aggchainManager
aggchainManager = admin;
// _initializeAggchainBase(
// _useDefaultVkeys, // false
// _useDefaultSigners, // false
// _initOwnedAggchainVKey, // not used
// _initAggchainVKeySelector // not used
// );
// set signer to trustedSequencer and threshold to 1
// handle trustedSequencerURL as empty string
if (bytes(trustedSequencerURL).length == 0) {
_addSignerInternal(trustedSequencer, "NO_URL"); // cannot be empty string
} else {
_addSignerInternal(trustedSequencer, trustedSequencerURL);
}
threshold = 1;
// update aggchainMultisigHash
_updateAggchainMultisigHash();
}
////////////////////////////////////////////////////////////
// Functions: pure //
////////////////////////////////////////////////////////////
/// @notice Validates the provided aggchain data and returns the computed aggchain parameters and vkey
/// @dev For ECDSA multisig, no data is needed as verification is done through signatures
/// @param aggchainData custom bytes provided by the chain, encoded in ABI solidity format
///
/// aggchain_vkey: set to zero to skip verification in the PP
/// aggchain_params: set to zero to skip verification in the PP
///
/// @return aggchainVKey Always returns bytes32(0) as ECDSA doesn't use verification keys
/// @return aggchainParams Always returns bytes32(0) as ECDSA doesn't use verification
/// @inheritdoc AggchainBase
///
function getVKeyAndAggchainParams(
bytes memory aggchainData
) public pure override returns (bytes32, bytes32) {
if (aggchainData.length != 0) {
revert InvalidAggchainDataLength();
}
// aggchainParams is not used in this implementation (signersHash and threshold are added directly in base)
return (bytes32(0), bytes32(0));
}
/**
* @notice Function to retrieve the current version of the contract.
* @return version String representation of the contract version
*/
function version() external pure returns (string memory) {
return AGGCHAIN_ECDSA_MULTISIG_VERSION;
}
////////////////////////////////////////////////////////////
// Functions: Callbacks //
////////////////////////////////////////////////////////////
/**
* @notice Callback when pessimistic proof is verified
* @dev For ECDSA multisig, just validates empty data and emits event
* @param aggchainData Must be empty for ECDSA implementation
* @inheritdoc IAggchainBase
*/
function onVerifyPessimistic(
bytes calldata aggchainData
) external onlyRollupManager {
if (aggchainData.length != 0) {
revert InvalidAggchainDataLength();
}
// Only aggchainVKeySelector is provided (bytes4 ABI-encoded as 32 bytes), no need to decode anything
// Just emit event to confirm verification
emit OnVerifyPessimisticECDSAMultisig();
}
////////////////////////////////////////////////////////////
// Overrides //
////////////////////////////////////////////////////////////
/**
* @notice This function is not supported in ECDSA multisig implementation
* @dev Overridden to prevent usage as ECDSA doesn't use verification keys
* @custom:security Always reverts with FunctionNotSupported error
*/
function enableUseDefaultVkeysFlag()
external
view
override
onlyAggchainManager
{
revert FunctionNotSupported();
}
/**
* @notice This function is not supported in ECDSA multisig implementation
* @dev Overridden to prevent usage as ECDSA doesn't use verification keys
* @custom:security Always reverts with FunctionNotSupported error
*/
function disableUseDefaultVkeysFlag()
external
view
override
onlyAggchainManager
{
revert FunctionNotSupported();
}
/**
* @notice This function is not supported in ECDSA multisig implementation
* @dev Overridden to prevent usage as ECDSA doesn't use verification keys
* @custom:security Always reverts with FunctionNotSupported error
*/
function addOwnedAggchainVKey(
bytes4,
bytes32
) external view override onlyAggchainManager {
revert FunctionNotSupported();
}
/**
* @notice This function is not supported in ECDSA multisig implementation
* @dev Overridden to prevent usage as ECDSA doesn't use verification keys
* @custom:security Always reverts with FunctionNotSupported error
*/
function updateOwnedAggchainVKey(
bytes4,
bytes32
) external view override onlyAggchainManager {
revert FunctionNotSupported();
}
/**
* @notice Returns the aggchain verification key - always returns zero in ECDSA multisig
* @dev Overridden to return bytes32(0) since verification keys are not used in ECDSA multisig
* @return aggchainVKey Always returns bytes32(0) as ECDSA doesn't use verification keys
*/
function getAggchainVKey(
bytes4
) public pure override returns (bytes32 aggchainVKey) {
// ECDSA multisig doesn't use vkeys, always return zero
return bytes32(0);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControlUpgradeable {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20PermitUpgradeable {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts 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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20Upgradeable {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20Upgradeable.sol";
import "../extensions/draft-IERC20PermitUpgradeable.sol";
import "../../../utils/AddressUpgradeable.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20Upgradeable {
using AddressUpgradeable for address;
function safeTransfer(
IERC20Upgradeable token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20Upgradeable token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20Upgradeable token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20Upgradeable token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20Upgradeable token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20PermitUpgradeable token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20Upgradeable token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165Upgradeable.sol";
import "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {
function __ERC165_init() internal onlyInitializing {
}
function __ERC165_init_unchained() internal onlyInitializing {
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165Upgradeable).interfaceId;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165Upgradeable {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.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);
}
}
}// 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);
}
}// 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);
}
}// 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);
}// 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);
}// 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();
}
}// 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();
}
}
}// 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();
}
}// 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);
}
}// 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);
}
}// 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();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (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;
}
}// 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
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuardTransient.sol)
pragma solidity ^0.8.24;
import {TransientSlot} from "./TransientSlot.sol";
/**
* @dev Variant of {ReentrancyGuard} that uses transient storage.
*
* NOTE: This variant only works on networks where EIP-1153 is available.
*
* _Available since v5.1._
*/
abstract contract ReentrancyGuardTransient {
using TransientSlot for *;
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant REENTRANCY_GUARD_STORAGE =
0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_reentrancyGuardEntered()) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
REENTRANCY_GUARD_STORAGE.asBoolean().tstore(true);
}
function _nonReentrantAfter() private {
REENTRANCY_GUARD_STORAGE.asBoolean().tstore(false);
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return REENTRANCY_GUARD_STORAGE.asBoolean().tload();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/TransientSlot.sol)
// This file was procedurally generated from scripts/generate/templates/TransientSlot.js.
pragma solidity ^0.8.24;
/**
* @dev Library for reading and writing value-types to specific transient storage slots.
*
* Transient slots are often used to store temporary values that are removed after the current transaction.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* * Example reading and writing values using transient storage:
* ```solidity
* contract Lock {
* using TransientSlot for *;
*
* // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
* bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542;
*
* modifier locked() {
* require(!_LOCK_SLOT.asBoolean().tload());
*
* _LOCK_SLOT.asBoolean().tstore(true);
* _;
* _LOCK_SLOT.asBoolean().tstore(false);
* }
* }
* ```
*
* TIP: Consider using this library along with {SlotDerivation}.
*/
library TransientSlot {
/**
* @dev UDVT that represent a slot holding a address.
*/
type AddressSlot is bytes32;
/**
* @dev Cast an arbitrary slot to a AddressSlot.
*/
function asAddress(bytes32 slot) internal pure returns (AddressSlot) {
return AddressSlot.wrap(slot);
}
/**
* @dev UDVT that represent a slot holding a bool.
*/
type BooleanSlot is bytes32;
/**
* @dev Cast an arbitrary slot to a BooleanSlot.
*/
function asBoolean(bytes32 slot) internal pure returns (BooleanSlot) {
return BooleanSlot.wrap(slot);
}
/**
* @dev UDVT that represent a slot holding a bytes32.
*/
type Bytes32Slot is bytes32;
/**
* @dev Cast an arbitrary slot to a Bytes32Slot.
*/
function asBytes32(bytes32 slot) internal pure returns (Bytes32Slot) {
return Bytes32Slot.wrap(slot);
}
/**
* @dev UDVT that represent a slot holding a uint256.
*/
type Uint256Slot is bytes32;
/**
* @dev Cast an arbitrary slot to a Uint256Slot.
*/
function asUint256(bytes32 slot) internal pure returns (Uint256Slot) {
return Uint256Slot.wrap(slot);
}
/**
* @dev UDVT that represent a slot holding a int256.
*/
type Int256Slot is bytes32;
/**
* @dev Cast an arbitrary slot to a Int256Slot.
*/
function asInt256(bytes32 slot) internal pure returns (Int256Slot) {
return Int256Slot.wrap(slot);
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(AddressSlot slot) internal view returns (address value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(AddressSlot slot, address value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(BooleanSlot slot) internal view returns (bool value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(BooleanSlot slot, bool value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Bytes32Slot slot) internal view returns (bytes32 value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Bytes32Slot slot, bytes32 value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Uint256Slot slot) internal view returns (uint256 value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Uint256Slot slot, uint256 value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Int256Slot slot) internal view returns (int256 value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Int256Slot slot, int256 value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.28;
import "./interfaces/IAgglayerGER.sol";
import "./interfaces/IPolygonZkEVMBridge.sol";
import "./interfaces/IPolygonRollupBase.sol";
import "./interfaces/IVerifierRollup.sol";
import "./lib/EmergencyManager.sol";
import "@openzeppelin/contracts-upgradeable4/token/ERC20/utils/SafeERC20Upgradeable.sol";
// @dev For ReentrancyGuardTransient there is no difference between upgradable and not upgradable contracts
import "@openzeppelin/contracts52/utils/ReentrancyGuardTransient.sol";
import "./lib/PolygonTransparentProxy.sol";
import "./lib/PolygonAccessControlUpgradeable.sol";
import "./lib/LegacyZKEVMStateVariables.sol";
import "./lib/PolygonConstantsBase.sol";
import "./interfaces/IPolygonPessimisticConsensus.sol";
import "./interfaces/ISP1Verifier.sol";
import "./interfaces/IAgglayerManager.sol";
import "./interfaces/IAggchainBase.sol";
import "./interfaces/IAgglayerGateway.sol";
import "./interfaces/IVersion.sol";
import "./lib/Hashes.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 AgglayerManager is
PolygonAccessControlUpgradeable,
EmergencyManager,
LegacyZKEVMStateVariables,
PolygonConstantsBase,
IAgglayerManager,
ReentrancyGuardTransient,
IVersion
{
using SafeERC20Upgradeable for IERC20Upgradeable;
/**
* @notice Struct which to store the rollup type data
* @param consensusImplementation Consensus implementation ( contains the consensus logic for the transparent proxy)
* @param address verifier
* @param forkID fork ID
* @param rollupVerifierType 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
* @param programVKey Hashed program that will be executed in case of using a "general purpose ZK verifier" e.g SP1
*/
struct RollupType {
address consensusImplementation;
address verifier;
uint64 forkID;
/// @custom:oz-renamed-from rollupCompatibilityID
/// @custom:oz-retyped-from uint8
VerifierType rollupVerifierType;
bool obsolete;
bytes32 genesis;
bytes32 programVKey;
}
/**
* @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 _legacyPendingStateTransitions Pending state mapping (deprecated)
* @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 _legacyLastPendingState Last pending state (deprecated)
* @param _legacyLastPendingStateConsolidated Last pending state consolidated (deprecated)
* @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 rollupVerifierType Rollup ID used for compatibility checks when upgrading
* @param lastPessimisticRoot Pessimistic info, currently contains the local balance tree and the local nullifier tree hashed
* @param programVKey Hashed program that will be executed in case of using a "general purpose ZK verifier" e.g SP1
*/
struct RollupData {
address rollupContract;
uint64 chainID;
address verifier;
uint64 forkID;
mapping(uint64 batchNum => bytes32) batchNumToStateRoot;
mapping(uint64 batchNum => SequencedBatchData) sequencedBatches;
/// @custom:oz-renamed-from pendingStateTransitions
mapping(uint256 pendingStateNum => PendingState) _legacyPendingStateTransitions;
bytes32 lastLocalExitRoot;
uint64 lastBatchSequenced;
uint64 lastVerifiedBatch;
/// @custom:oz-renamed-from lastPendingState
uint64 _legacyLastPendingState;
/// @custom:oz-renamed-from lastPendingStateConsolidated
uint64 _legacyLastPendingStateConsolidated;
uint64 lastVerifiedBatchBeforeUpgrade;
uint64 rollupTypeID;
/// @custom:oz-renamed-from rollupCompatibilityID
/// @custom:oz-retyped-from uint8
VerifierType rollupVerifierType;
bytes32 lastPessimisticRoot;
bytes32 programVKey;
}
/**
* @notice Struct to return all the necessary rollup info: VerifierType StateTransition
* @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 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 _legacyLastPendingState Last pending state (deprecated)
* @param _legacyLastPendingStateConsolidated Last pending state consolidated (deprecated)
* @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 rollupVerifierType Rollup ID used for compatibility checks when upgrading
*/
struct RollupDataReturn {
address rollupContract;
uint64 chainID;
address verifier;
uint64 forkID;
bytes32 lastLocalExitRoot;
uint64 lastBatchSequenced;
uint64 lastVerifiedBatch;
uint64 _legacyLastPendingState;
uint64 _legacyLastPendingStateConsolidated;
uint64 lastVerifiedBatchBeforeUpgrade;
uint64 rollupTypeID;
VerifierType rollupVerifierType;
}
/**
* @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 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 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 rollupVerifierType Rollup ID used for compatibility checks when upgrading
* @param lastPessimisticRoot Pessimistic info, currently contains the local balance tree and the local nullifier tree hashed
* @param programVKey Hashed program that will be executed in case of using a "general purpose ZK verifier" e.g SP1
*/
struct RollupDataReturnV2 {
address rollupContract;
uint64 chainID;
address verifier;
uint64 forkID;
bytes32 lastLocalExitRoot;
uint64 lastBatchSequenced;
uint64 lastVerifiedBatch;
uint64 lastVerifiedBatchBeforeUpgrade;
uint64 rollupTypeID;
VerifierType rollupVerifierType;
bytes32 lastPessimisticRoot;
bytes32 programVKey;
}
// Modulus zkSNARK
uint256 internal constant _RFIELD =
21888242871839275222246405745257275088548364400416034343698204186575808495617;
// 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");
// Current rollup manager version
string public constant ROLLUP_MANAGER_VERSION = "v1.0.0";
// Hardcoded address used to indicate that this address triggered in an event should not be considered as valid.
address private constant _NO_ADDRESS =
0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF;
// Global Exit Root address
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
IAgglayerGER public immutable globalExitRootManager;
// PolygonZkEVM Bridge Address
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
IPolygonZkEVMBridge public immutable bridgeAddress;
// POL token address
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
IERC20Upgradeable public immutable pol;
// Polygon Verifier Gateway address
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
IAgglayerGateway public immutable aggLayerGateway;
// Number of rollup types added, every new type will be assigned sequentially a new ID
uint32 public rollupTypeCount;
// Rollup type mapping
/// @custom:oz-retyped-from PolygonRollupManagerPrevious.RollupType
mapping(uint32 rollupTypeID => RollupType) public rollupTypeMap;
// Number of rollups added, every new rollup will be assigned sequentially a new ID
uint32 public rollupCount;
// Rollups ID mapping
/// @custom:oz-retyped-from PolygonRollupManagerPrevious.RollupData
mapping(uint32 rollupID => RollupData) internal _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
/// @custom:oz-renamed-from trustedAggregatorTimeout
uint64 internal __legacyTrustedAggregatorTimeout;
// Once a pending state exceeds this timeout it can be consolidated (deprecated)
/// @custom:oz-renamed-from pendingStateTimeout
uint64 internal __legacyPendingStateTimeout;
// Time target of the verification of a batch
// Adaptively 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;
// 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;
// Mapping to track chains in migration
mapping(uint32 rollupID => bool) public isRollupMigrating;
/**
* @dev Emitted when a new rollup type is added
*/
event AddNewRollupType(
uint32 indexed rollupTypeID,
address consensusImplementation,
address verifier,
uint64 forkID,
VerifierType rollupVerifierType,
bytes32 genesis,
string description,
bytes32 programVKey
);
/**
* @dev Emitted when a a rollup 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,
VerifierType rollupVerifierType,
uint64 lastVerifiedBatchBeforeUpgrade,
bytes32 programVKey,
bytes32 initPessimisticRoot
);
/**
* @dev Emitted when a rollup is updated
*/
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 the trusted aggregator verifies batches
*/
event VerifyBatchesTrustedAggregator(
uint32 indexed rollupID,
uint64 numBatch,
bytes32 stateRoot,
bytes32 exitRoot,
address indexed aggregator
);
/**
* @dev Emitted when rollback batches
*/
event RollbackBatches(
uint32 indexed rollupID,
uint64 indexed targetBatch,
bytes32 accInputHashToRollback
);
/**
* @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);
/**
* @dev Emitted when rollup manager is upgraded
*/
event UpdateRollupManagerVersion(string rollupManagerVersion);
/**
* @notice Emitted when a ALGateway or Pessimistic chain verifies a pessimistic proof
* @param rollupID Rollup ID
* @param prevPessimisticRoot Previous pessimistic root
* @param newPessimisticRoot New pessimistic root
* @param prevLocalExitRoot Previous local exit root
* @param newLocalExitRoot New local exit root
* @param l1InfoRoot L1 info root
* @param trustedAggregator Trusted aggregator address
*/
event VerifyPessimisticStateTransition(
uint32 indexed rollupID,
bytes32 prevPessimisticRoot,
bytes32 newPessimisticRoot,
bytes32 prevLocalExitRoot,
bytes32 newLocalExitRoot,
bytes32 l1InfoRoot,
address indexed trustedAggregator
);
/**
* @dev Emitted when a new rollup is created based on a rollupType
*/
event CreateNewAggchain(
uint32 indexed rollupID,
uint32 rollupTypeID,
address rollupAddress,
uint64 chainID,
uint8 rollupVerifierType,
bytes initializeBytesAggchain
);
/**
* @dev Emitted when `initMigration` is called
* @param rollupID Rollup ID that is being migrated
* @param newRollupTypeID New rollup type ID that the rollup will be migrated to
*/
event InitMigration(uint32 indexed rollupID, uint32 newRollupTypeID);
/**
* @dev Emitted when a rollup completes the migration to Pessimistic or ALGateway, just after proving bootstrapped batch
* @param rollupID Rollup ID that completed the migration
*/
event CompletedMigration(uint32 indexed rollupID);
/**
* @param _globalExitRootManager Global exit root manager address
* @param _pol POL token address
* @param _bridgeAddress Bridge address
* @param _aggLayerGateway Polygon Verifier Gateway address
*/
constructor(
IAgglayerGER _globalExitRootManager,
IERC20Upgradeable _pol,
IPolygonZkEVMBridge _bridgeAddress,
IAgglayerGateway _aggLayerGateway
) {
// Check non zero inputs
if (
address(_globalExitRootManager) == address(0) ||
address(_pol) == address(0) ||
address(_bridgeAddress) == address(0) ||
address(_aggLayerGateway) == address(0)
) {
revert InvalidConstructorInputs();
}
globalExitRootManager = _globalExitRootManager;
pol = _pol;
bridgeAddress = _bridgeAddress;
aggLayerGateway = _aggLayerGateway;
// Disable initializers on the implementation following the best practices
_disableInitializers();
}
/**
* Initializer function to set new rollup manager version
*/
function initialize() external virtual reinitializer(5) {
emit UpdateRollupManagerVersion(ROLLUP_MANAGER_VERSION);
}
///////////////////////////////////////
// Rollups management functions
///////////////////////////////////////
////////////////
// Rollups Types
////////////////
/**
* @notice Add a new rollup type
* @param consensusImplementation Consensus implementation
* @param verifier Verifier address
* @param forkID ForkID of the verifier
* @param rollupVerifierType rollup verifier type
* @param genesis Genesis block of the rollup
* @param description Description of the rollup type
* @param programVKey Hashed program that will be executed in case of using a "general purpose ZK verifier" e.g SP1
*/
function addNewRollupType(
address consensusImplementation,
address verifier,
uint64 forkID,
VerifierType rollupVerifierType,
bytes32 genesis,
string memory description,
bytes32 programVKey
) external onlyRole(_ADD_ROLLUP_TYPE_ROLE) {
// Check proposed address is not this contract to avoid self-referential loops causing infinite delegate calls
if (consensusImplementation == address(this)) {
revert InvalidImplementationAddress();
}
uint32 rollupTypeID = ++rollupTypeCount;
if (rollupVerifierType == VerifierType.Pessimistic) {
// No genesis on pessimistic rollups
if (genesis != bytes32(0)) revert InvalidRollupType();
} else if (rollupVerifierType == VerifierType.ALGateway) {
// Those params should be zero for ALGateway rollup types
if (
verifier != address(0) ||
forkID != 0 ||
genesis != bytes32(0) ||
programVKey != bytes32(0)
) revert InvalidRollupType();
} else if (rollupVerifierType == VerifierType.StateTransition) {
// No programVKey on state transition rollups
if (programVKey != bytes32(0)) revert InvalidRollupType();
} else {
// unreachable code since solidity enforces the enum input rollupVerifierType to be one of the enum values
revert InvalidRollupType();
}
rollupTypeMap[rollupTypeID] = RollupType({
consensusImplementation: consensusImplementation,
verifier: verifier,
forkID: forkID,
rollupVerifierType: rollupVerifierType,
obsolete: false,
genesis: genesis,
programVKey: programVKey
});
emit AddNewRollupType(
rollupTypeID,
consensusImplementation,
verifier,
forkID,
rollupVerifierType,
genesis,
description,
programVKey
);
}
/**
* @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) {
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 initializeBytesAggchain Encoded params to initialize the chain. Each aggchain has its encoded params.
* @dev in case of rollupType state transition or pessimistic, the encoded params
* are the following: (address admin, address sequencer, address gasTokenAddress, string sequencerURL, string networkName)
*/
function attachAggchainToAL(
uint32 rollupTypeID,
uint64 chainID,
bytes memory initializeBytesAggchain
) 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) {
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 to rollup id mapping
chainIDToRollupID[chainID] = rollupID;
// Set rollup address to rollup id mapping
rollupAddressToID[rollupAddress] = rollupID;
// Set rollup data
RollupData storage rollup = _rollupIDToRollupData[rollupID];
rollup.rollupContract = rollupAddress;
rollup.chainID = chainID;
rollup.rollupTypeID = rollupTypeID;
rollup.rollupVerifierType = rollupType.rollupVerifierType;
if (rollupType.rollupVerifierType == VerifierType.ALGateway) {
// Emit create new aggchain event
emit CreateNewAggchain(
rollupID,
rollupTypeID,
rollupAddress,
chainID,
uint8(rollupType.rollupVerifierType),
initializeBytesAggchain
);
// This event is emitted for backwards compatibility
/// @dev the address is hardcoded as it doesn't apply for aggchains and zero address is used for ether
emit CreateNewRollup(
rollupID,
rollupTypeID,
rollupAddress,
chainID,
_NO_ADDRESS
);
address aggchainManager = abi.decode(
initializeBytesAggchain,
(address)
);
// Set the aggchain manager, aggchain contract will be initialized later
// through the aggchain manager
IAggchainBase(rollupAddress).initAggchainManager(aggchainManager);
} else {
// assign non ALGateway values to rollup data
rollup.forkID = rollupType.forkID;
rollup.verifier = rollupType.verifier;
rollup.batchNumToStateRoot[0] = rollupType.genesis;
rollup.programVKey = rollupType.programVKey;
// custom parsing of the initializeBytesAggchain for a sate transition or pessimistic rollup
(
address admin,
address sequencer,
address gasTokenAddress,
string memory sequencerURL,
string memory networkName
) = abi.decode(
initializeBytesAggchain,
(address, address, address, string, string)
);
// Emit create new rollup event
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 initRoot Genesis block for StateTransitionChains & localExitRoot for pessimistic chain
* @param rollupVerifierType Compatibility ID for the added rollup
* @param programVKey Hashed program that will be executed in case of using a "general purpose ZK verifier" e.g SP1
* @param initPessimisticRoot Pessimistic root to init the chain.
*/
function addExistingRollup(
address rollupAddress,
address verifier,
uint64 forkID,
uint64 chainID,
bytes32 initRoot,
VerifierType rollupVerifierType,
bytes32 programVKey,
bytes32 initPessimisticRoot
) 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();
}
// Check proposed address is not this contract to avoid self-referential loops causing infinite delegate calls
if (rollupAddress == address(this) || rollupAddress.code.length == 0) {
revert InvalidImplementationAddress();
}
// Increment rollup count
uint32 rollupID = ++rollupCount;
// Set chainID nullifier
chainIDToRollupID[chainID] = rollupID;
// Store rollup data
rollupAddressToID[address(rollupAddress)] = rollupID;
RollupData storage rollup = _rollupIDToRollupData[rollupID];
rollup.rollupContract = rollupAddress;
rollup.forkID = forkID;
rollup.verifier = verifier;
rollup.chainID = chainID;
rollup.rollupVerifierType = rollupVerifierType;
// Check verifier type
if (rollupVerifierType == VerifierType.Pessimistic) {
rollup.programVKey = programVKey;
rollup.lastPessimisticRoot = initPessimisticRoot;
rollup.lastLocalExitRoot = initRoot;
if (verifier.code.length == 0) {
revert InvalidVerifierAddress();
}
} else if (rollupVerifierType == VerifierType.ALGateway) {
if (
verifier != address(0) ||
forkID != 0 ||
programVKey != bytes32(0)
) {
revert InvalidInputsForRollupType();
}
rollup.lastPessimisticRoot = initPessimisticRoot;
rollup.lastLocalExitRoot = initRoot;
} else {
if (
programVKey != bytes32(0) || initPessimisticRoot != bytes32(0)
) {
revert InvalidInputsForRollupType();
}
rollup.batchNumToStateRoot[0] = initRoot;
if (verifier.code.length == 0) {
revert InvalidVerifierAddress();
}
}
emit AddExistingRollup(
rollupID,
forkID,
address(rollupAddress),
chainID,
rollupVerifierType,
0,
programVKey,
initPessimisticRoot
);
}
/**
* @notice Upgrade an existing rollup from the rollup admin address
* This address is able to update 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 {
RollupData storage rollup = _rollupIDToRollupData[
rollupAddressToID[address(rollupContract)]
];
if (rollup.rollupVerifierType == VerifierType.ALGateway) {
// Check aggchain manager is msg.sender
if (
IAggchainBase(address(rollupContract)).aggchainManager() !=
msg.sender
) {
revert OnlyAggchainManager();
}
// Check AGGCHAIN_TYPE is the same (both are ALGateway at this point)
if (
IAggchainBase(address(rollupContract)).AGGCHAIN_TYPE() !=
IAggchainBase(
rollupTypeMap[newRollupTypeID].consensusImplementation
).AGGCHAIN_TYPE()
) {
revert UpdateNotCompatible();
}
} else {
// Check admin of the network is msg.sender
if (
IPolygonRollupBase(address(rollupContract)).admin() !=
msg.sender
) {
revert OnlyRollupAdmin();
}
// Check all sequenced batches are verified
if (rollup.lastBatchSequenced != rollup.lastVerifiedBatch) {
revert AllSequencedMustBeVerified();
}
}
// Not allowed to update to an older rollup type id, only supported from updateRollup function
// Rollups added via 'addExistingRollup' has rollupTypeID = 0
if (rollup.rollupTypeID >= newRollupTypeID) {
revert UpdateToOldRollupTypeID();
}
// note that for rollups via 'addExistingRollup', the rollupTypeID is set to 0
// Admin can't update to a different rollup type
if (
rollup.rollupVerifierType !=
rollupTypeMap[newRollupTypeID].rollupVerifierType
) {
revert UpdateNotCompatible();
}
_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) {
uint32 rollupID = rollupAddressToID[address(rollupContract)];
RollupData storage rollup = _rollupIDToRollupData[rollupID];
// Only allow update rollupVerifierType when updating to ALGateway
if (
rollupTypeMap[newRollupTypeID].rollupVerifierType !=
VerifierType.ALGateway &&
rollup.rollupVerifierType !=
rollupTypeMap[newRollupTypeID].rollupVerifierType
) {
revert UpdateNotCompatible();
}
_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) {
revert RollupTypeObsolete();
}
// Update rollup parameters
rollup.verifier = newRollupType.verifier;
rollup.forkID = newRollupType.forkID;
rollup.programVKey = newRollupType.programVKey;
rollup.rollupTypeID = newRollupTypeID;
rollup.rollupVerifierType = newRollupType.rollupVerifierType;
uint64 lastVerifiedBatch = getLastVerifiedBatch(rollupID);
rollup.lastVerifiedBatchBeforeUpgrade = lastVerifiedBatch;
// Upgrade rollup
rollupContract.upgradeToAndCall(
newRollupType.consensusImplementation,
upgradeData
);
emit UpdateRollup(rollupID, newRollupTypeID, lastVerifiedBatch);
}
/**
* @notice Function to init migration to PP or ALGateway
* @param rollupID Rollup ID that is being migrated
* @param newRollupTypeID New rollup type ID that the rollup will be migrated to
* @param upgradeData Upgrade data
*/
function initMigration(
uint32 rollupID,
uint32 newRollupTypeID,
bytes memory upgradeData
) external onlyRole(_UPDATE_ROLLUP_ROLE) {
/// @dev Rollup existence check is done at `_updateRollup`function
RollupData storage rollup = _rollupIDToRollupData[rollupID];
// Only for StateTransition chains
require(
rollup.rollupVerifierType == VerifierType.StateTransition,
OnlyStateTransitionChains()
);
// No pending batches to verify allowed before migration
if (rollup.lastBatchSequenced != rollup.lastVerifiedBatch) {
revert AllSequencedMustBeVerified();
}
// NewRollupType must be pessimistic or ALGateway
require(
rollupTypeMap[newRollupTypeID].rollupVerifierType !=
VerifierType.StateTransition,
NewRollupTypeMustBePessimisticOrALGateway()
);
// Add rollupID to migration mapping
isRollupMigrating[rollupID] = true;
// Update rollup type to new type
_updateRollup(
ITransparentUpgradeableProxy(rollup.rollupContract),
newRollupTypeID,
upgradeData
);
// Emit event
emit InitMigration(rollupID, newRollupTypeID);
}
/**
* @notice Rollback batches of the target rollup
* Only applies to state transition rollups
* @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 nonReentrant {
// 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];
if (rollup.rollupVerifierType != VerifierType.StateTransition) {
revert OnlyStateTransitionChains();
}
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;
// 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 overwriting sequencedBatches
if (newSequencedBatches == 0) {
revert MustSequenceSomeBatch();
}
RollupData storage rollup = _rollupIDToRollupData[rollupID];
if (rollup.rollupVerifierType != VerifierType.StateTransition) {
revert OnlyStateTransitionChains();
}
// 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
});
emit OnSequenceBatches(rollupID, newLastBatchSequenced);
return newLastBatchSequenced;
}
/**
* @notice Allows a trusted aggregator to verify multiple batches
* @param rollupID Rollup identifier
* @param pendingStateNum Init pending state, 0 if consolidated state is used (deprecated)
* @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) {
// Pending state became deprecated,
// It's still there just to have backwards compatibility interface
if (pendingStateNum != 0) {
revert PendingStateNumExist();
}
RollupData storage rollup = _rollupIDToRollupData[rollupID];
if (rollup.rollupVerifierType != VerifierType.StateTransition) {
revert OnlyStateTransitionChains();
}
_verifyAndRewardBatches(
rollup,
initNumBatch,
finalNewBatch,
newLocalExitRoot,
newStateRoot,
beneficiary,
proof
);
// Consolidate state
rollup.lastVerifiedBatch = finalNewBatch;
rollup.batchNumToStateRoot[finalNewBatch] = newStateRoot;
rollup.lastLocalExitRoot = newLocalExitRoot;
// 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 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 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 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
);
// Calculate the snark input
uint256 inputSnark = uint256(sha256(snarkHashBytes)) % _RFIELD;
// Verify proof
if (
!IVerifierRollup(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
IPolygonRollupBase(rollup.rollupContract).onVerifyBatches(
finalNewBatch,
newStateRoot,
msg.sender
);
}
/**
* @notice Allows a trusted aggregator to verify pessimistic proof
* @param rollupID Rollup identifier
* @param l1InfoTreeLeafCount Count of the L1InfoTree leaf that will be used to verify imported bridge exits
* @param newLocalExitRoot New local exit root
* @param newPessimisticRoot New pessimistic information, Hash(localBalanceTreeRoot, nullifierTreeRoot)
* @param proof SP1 proof (Plonk)
* @param aggchainData Specific custom data to verify Aggregation layer chains
* @dev A reentrancy measure has been applied because this function calls `onVerifyPessimistic`, is an open function implemented by the aggchains
* @dev the function can not be a view because the nonReentrant uses a transient storage variable
*/
function verifyPessimisticTrustedAggregator(
uint32 rollupID,
uint32 l1InfoTreeLeafCount,
bytes32 newLocalExitRoot,
bytes32 newPessimisticRoot,
bytes calldata proof,
bytes calldata aggchainData
) external onlyRole(_TRUSTED_AGGREGATOR_ROLE) nonReentrant {
RollupData storage rollup = _rollupIDToRollupData[rollupID];
// Not for state transition chains
if (rollup.rollupVerifierType == VerifierType.StateTransition) {
revert StateTransitionChainsNotAllowed();
}
// Not aggchainData for VerifierType.Pessimistic
if (
rollup.rollupVerifierType == VerifierType.Pessimistic &&
aggchainData.length != 0
) {
revert AggchainDataMustBeZeroForPessimisticVerifierType();
}
// Check l1InfoTreeLeafCount has a valid l1InfoTreeRoot
bytes32 l1InfoRoot = globalExitRootManager.l1InfoRootMap(
l1InfoTreeLeafCount
);
if (l1InfoRoot == bytes32(0)) {
revert L1InfoTreeLeafCountInvalid();
}
// In case of a chain in migration, the inputs are a special case.
if (isRollupMigrating[rollupID]) {
// If we are migrating, the proof is proving a "bootstrapCertificate" containing all the bridges involved in the network since the genesis.
// It's a hard requirement that the newLocalExitRoot matches the current lastLocalExitRoot meaning that the certificates covers all the bridges
/// @dev If the lastLocalExitRoot is zero, it means that the rollup has never verified a batch with bridges.
/// In this special case, newLocalExitRoot must also be zero as defined in the PP program circuit.
require(
newLocalExitRoot == rollup.lastLocalExitRoot,
InvalidNewLocalExitRoot()
);
// In this special case, we consider lastLocalExitRoot is zero.
// This is intentional, as we need a valid prover input.
// Since the proof includes all bridges involved in the network, we assume
// lastLocalExitRoot is bytes32(0), and the expectedNewLocalExitRoot will
// already contain the full network state (lastLocalExitRoot).
rollup.lastLocalExitRoot = bytes32(0);
// Finally, after proving the "bootstrapCertificate", the migration will be completed
isRollupMigrating[rollupID] = false;
// Emit event
emit CompletedMigration(rollupID);
}
bytes memory inputPessimisticBytes = _getInputPessimisticBytes(
rollupID,
rollup,
l1InfoRoot,
newLocalExitRoot,
newPessimisticRoot,
aggchainData
);
if (rollup.rollupVerifierType == VerifierType.ALGateway) {
// Verify proof. The pessimistic proof selector is attached at the first 4 bytes of the proof
// proof[0:4]: 4 bytes selector pp
// proof[4:8]: 4 bytes selector SP1 verifier
// proof[8:]: proof
aggLayerGateway.verifyPessimisticProof(
inputPessimisticBytes,
proof
);
} else {
// Verify proof
ISP1Verifier(rollup.verifier).verifyProof(
rollup.programVKey,
inputPessimisticBytes,
proof
);
}
// Update aggregation parameters
lastAggregationTimestamp = uint64(block.timestamp);
// Consolidate state
bytes32 prevLocalExitRoot = rollup.lastLocalExitRoot;
rollup.lastLocalExitRoot = newLocalExitRoot;
bytes32 prevPessimisticRoot = rollup.lastPessimisticRoot;
rollup.lastPessimisticRoot = newPessimisticRoot;
// Interact with globalExitRootManager
globalExitRootManager.updateExitRoot(getRollupExitRoot());
// Same event as verifyBatches to support current bridge service to synchronize everything
/// @dev moved newLocalExitRoot to aux variable to avoid stack too deep errors at compilation
bytes32 newLocalExitRootAux = newLocalExitRoot;
emit VerifyBatchesTrustedAggregator(
rollupID,
0, // final batch: does not apply in pessimistic
bytes32(0), // new state root: does not apply in pessimistic
newLocalExitRootAux,
msg.sender
);
/// @dev emit a second event with more data, not updated/removed the other one for backwards compatibility reasons
emit VerifyPessimisticStateTransition(
rollupID,
prevPessimisticRoot,
newPessimisticRoot,
prevLocalExitRoot,
newLocalExitRootAux,
l1InfoRoot,
msg.sender
);
if (rollup.rollupVerifierType == VerifierType.ALGateway) {
// Allow chains to manage customData
// Callback to the rollup address
IAggchainBase(rollup.rollupContract).onVerifyPessimistic(
aggchainData
);
}
}
////////////////////////
// Emergency state functions
////////////////////////
/**
* @notice Function to activate emergency state, which also enables the emergency mode on both AgglayerManager 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 AgglayerManager 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 AgglayerManager 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 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 remaining 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] = Hashes.efficientKeccak256(
tmpTree[i * 2],
currentZeroHashHeight
);
} else {
nextTmpTree[i] = Hashes.efficientKeccak256(
tmpTree[i * 2],
tmpTree[(i * 2) + 1]
);
}
}
// Update tree variables
tmpTree = nextTmpTree;
currentNodes = nextIterationNodes;
currentZeroHashHeight = Hashes.efficientKeccak256(
currentZeroHashHeight,
currentZeroHashHeight
);
remainingLevels--;
}
bytes32 currentRoot = tmpTree[0];
// Calculate remaining levels, since it's a sequential merkle tree, the rest of the tree are zeroes
for (uint256 i = 0; i < remainingLevels; i++) {
currentRoot = Hashes.efficientKeccak256(
currentRoot,
currentZeroHashHeight
);
currentZeroHashHeight = Hashes.efficientKeccak256(
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) {
return rollup.lastVerifiedBatch;
}
/**
* @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 instead of the automatic public view one,
* because in a future might change the behavior and we will be able to maintain 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 pessimistic input bytes
* @param rollupID Rollup id used to calculate the input snark bytes
* @param l1InfoTreeRoot L1 Info tree root to proof imported bridges
* @param newLocalExitRoot New local exit root
* @param newPessimisticRoot New pessimistic information, Hash(localBalanceTreeRoot, nullifierTreeRoot)
* @param aggchainData Specific custom data to verify Aggregation layer chains
*/
function getInputPessimisticBytes(
uint32 rollupID,
bytes32 l1InfoTreeRoot,
bytes32 newLocalExitRoot,
bytes32 newPessimisticRoot,
bytes calldata aggchainData
) external view returns (bytes memory) {
return
_getInputPessimisticBytes(
rollupID,
_rollupIDToRollupData[rollupID],
l1InfoTreeRoot,
newLocalExitRoot,
newPessimisticRoot,
aggchainData
);
}
/**
* @notice Function to calculate the input snark bytes
* @param rollupID Rollup identifier
* @param rollup Rollup data storage pointer
* @param l1InfoTreeRoot L1 Info tree root to proof imported bridges
* @param newLocalExitRoot New local exit root
* @param newPessimisticRoot New pessimistic information, Hash(localBalanceTreeRoot, nullifierTreeRoot)
*/
function _getInputPessimisticBytes(
uint32 rollupID,
RollupData storage rollup,
bytes32 l1InfoTreeRoot,
bytes32 newLocalExitRoot,
bytes32 newPessimisticRoot,
bytes calldata aggchainData
) internal view returns (bytes memory inputPessimisticBytes) {
// Different consensusHash and encoding if the rollup is ALGateway or pessimistic
if (rollup.rollupVerifierType == VerifierType.ALGateway) {
bytes32 aggchainHash = IAggchainBase(rollup.rollupContract)
.getAggchainHash(aggchainData);
inputPessimisticBytes = abi.encodePacked(
rollup.lastLocalExitRoot,
rollup.lastPessimisticRoot,
l1InfoTreeRoot,
rollupID,
aggchainHash,
newLocalExitRoot,
newPessimisticRoot
);
} else {
bytes32 consensusHash = IPolygonPessimisticConsensus(
address(rollup.rollupContract)
).getConsensusHash();
inputPessimisticBytes = abi.encodePacked(
rollup.lastLocalExitRoot,
rollup.lastPessimisticRoot,
l1InfoTreeRoot,
rollupID,
consensusHash,
newLocalExitRoot,
newPessimisticRoot
);
}
}
/**
* @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 data: VerifierType StateTransition
* @param rollupID Rollup identifier
*/
function rollupIDToRollupData(
uint32 rollupID
) public view returns (RollupDataReturn memory rollupData) {
RollupData storage rollup = _rollupIDToRollupData[rollupID];
rollupData.rollupContract = rollup.rollupContract;
rollupData.chainID = rollup.chainID;
rollupData.verifier = rollup.verifier;
rollupData.forkID = rollup.forkID;
rollupData.lastLocalExitRoot = rollup.lastLocalExitRoot;
rollupData.lastBatchSequenced = rollup.lastBatchSequenced;
rollupData.lastVerifiedBatch = rollup.lastVerifiedBatch;
rollupData._legacyLastPendingState = rollup._legacyLastPendingState;
rollupData._legacyLastPendingStateConsolidated = rollup
._legacyLastPendingStateConsolidated;
rollupData.lastVerifiedBatchBeforeUpgrade = rollup
.lastVerifiedBatchBeforeUpgrade;
rollupData.rollupTypeID = rollup.rollupTypeID;
rollupData.rollupVerifierType = rollup.rollupVerifierType;
}
/**
* @notice Get rollup data: VerifierType State transition
* @param rollupID Rollup identifier
*/
function rollupIDToRollupDataDeserialized(
uint32 rollupID
)
public
view
returns (
address rollupContract,
uint64 chainID,
address verifier,
uint64 forkID,
bytes32 lastLocalExitRoot,
uint64 lastBatchSequenced,
uint64 lastVerifiedBatch,
uint64 legacyLastPendingState,
uint64 legacyLastPendingStateConsolidated,
uint64 lastVerifiedBatchBeforeUpgrade,
uint64 rollupTypeID,
VerifierType rollupVerifierType
)
{
RollupData storage rollup = _rollupIDToRollupData[rollupID];
rollupContract = rollup.rollupContract;
chainID = rollup.chainID;
verifier = rollup.verifier;
forkID = rollup.forkID;
lastLocalExitRoot = rollup.lastLocalExitRoot;
lastBatchSequenced = rollup.lastBatchSequenced;
lastVerifiedBatch = rollup.lastVerifiedBatch;
legacyLastPendingState = rollup._legacyLastPendingState;
legacyLastPendingStateConsolidated = rollup
._legacyLastPendingStateConsolidated;
lastVerifiedBatchBeforeUpgrade = rollup.lastVerifiedBatchBeforeUpgrade;
rollupTypeID = rollup.rollupTypeID;
rollupVerifierType = rollup.rollupVerifierType;
}
/**
* @notice Get rollup data: VerifierType Pessimistic
* @param rollupID Rollup identifier
*/
function rollupIDToRollupDataV2(
uint32 rollupID
) public view returns (RollupDataReturnV2 memory rollupData) {
RollupData storage rollup = _rollupIDToRollupData[rollupID];
rollupData.rollupContract = rollup.rollupContract;
rollupData.chainID = rollup.chainID;
rollupData.verifier = rollup.verifier;
rollupData.forkID = rollup.forkID;
rollupData.lastLocalExitRoot = rollup.lastLocalExitRoot;
rollupData.lastBatchSequenced = rollup.lastBatchSequenced;
rollupData.lastVerifiedBatch = rollup.lastVerifiedBatch;
rollupData.lastVerifiedBatchBeforeUpgrade = rollup
.lastVerifiedBatchBeforeUpgrade;
rollupData.rollupTypeID = rollup.rollupTypeID;
rollupData.rollupVerifierType = rollup.rollupVerifierType;
rollupData.lastPessimisticRoot = rollup.lastPessimisticRoot;
rollupData.programVKey = rollup.programVKey;
}
/**
* @notice Get rollup data deserialized
* @dev A deserialized version of the rollup data done for a better parsing from etherscan
* @param rollupID Rollup identifier
*/
function rollupIDToRollupDataV2Deserialized(
uint32 rollupID
)
public
view
returns (
address rollupContract,
uint64 chainID,
address verifier,
uint64 forkID,
bytes32 lastLocalExitRoot,
uint64 lastBatchSequenced,
uint64 lastVerifiedBatch,
uint64 lastVerifiedBatchBeforeUpgrade,
uint64 rollupTypeID,
VerifierType rollupVerifierType,
bytes32 lastPessimisticRoot,
bytes32 programVKey
)
{
RollupData storage rollup = _rollupIDToRollupData[rollupID];
rollupContract = rollup.rollupContract;
chainID = rollup.chainID;
verifier = rollup.verifier;
forkID = rollup.forkID;
lastLocalExitRoot = rollup.lastLocalExitRoot;
lastBatchSequenced = rollup.lastBatchSequenced;
lastVerifiedBatch = rollup.lastVerifiedBatch;
lastVerifiedBatchBeforeUpgrade = rollup.lastVerifiedBatchBeforeUpgrade;
rollupTypeID = rollup.rollupTypeID;
rollupVerifierType = rollup.rollupVerifierType;
lastPessimisticRoot = rollup.lastPessimisticRoot;
programVKey = rollup.programVKey;
}
/**
* @notice Function to retrieve the current version of the contract.
* @return version of the contract.
*/
function version() external pure returns (string memory) {
return ROLLUP_MANAGER_VERSION;
}
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.28;
import "./IAggchainSigners.sol";
/**
* @title IAggchainBaseEvents
* @notice Events emitted by AggchainBase implementations
*/
interface IAggchainBaseEvents {
/**
* @notice Emitted when the admin adds an aggchain verification key.
* @param selector The selector of the verification key to add.
* @param newAggchainVKey The new aggchain verification key.
*/
event AddAggchainVKey(bytes4 selector, bytes32 newAggchainVKey);
/**
* @notice Emitted when the admin updates the aggchain verification key.
* @param selector The selector of the verification key to update.
* @param previousAggchainVKey The previous aggchain verification key.
* @param newAggchainVKey The new new aggchain verification key.
*/
event UpdateAggchainVKey(
bytes4 selector,
bytes32 previousAggchainVKey,
bytes32 newAggchainVKey
);
/**
* @notice Emitted when the admin set the flag useDefaultVkeys to true.
*/
event EnableUseDefaultVkeysFlag();
/**
* @notice Emitted when the admin set the flag useDefaultVkeys to false.
*/
event DisableUseDefaultVkeysFlag();
/**
* @notice Emitted when the admin set the flag useDefaultSigners to true.
*/
event EnableUseDefaultSignersFlag();
/**
* @notice Emitted when the admin set the flag useDefaultSigners to false.
*/
event DisableUseDefaultSignersFlag();
/// @dev Emitted when the aggchainManager starts the two-step transfer role setting a new pending newAggchainManager
/// @param currentAggchainManager The current pending aggchainManager
/// @param newPendingAggchainManager The new pending aggchainManager
event TransferAggchainManagerRole(
address currentAggchainManager,
address newPendingAggchainManager
);
/// @notice Emitted when the pending aggchainManager accepts the aggchainManager role
/// @param oldAggchainManager The old aggchainManager
/// @param newAggchainManager The new aggchainManager
event AcceptAggchainManagerRole(
address oldAggchainManager,
address newAggchainManager
);
/**
* @notice Emitted when metadata is set or updated.
* @param key The metadata key.
* @param value The metadata value.
*/
event AggchainMetadataSet(string indexed key, string value);
/**
* @notice Emitted when the aggchain metadata manager is set.
* @param oldAggchainMetadataManager The old aggchain metadata manager.
* @param newAggchainMetadataManager The new aggchain metadata manager.
*/
event SetAggchainMetadataManager(
address oldAggchainMetadataManager,
address newAggchainMetadataManager
);
}
/**
* @title IAggchainBaseErrors
* @notice Error definitions for AggchainBase implementations
*/
interface IAggchainBaseErrors {
/// @notice Thrown when trying to add zero value verification key.
error ZeroValueAggchainVKey();
/// @notice Thrown when trying to add an aggchain verification key that already exists.
error OwnedAggchainVKeyAlreadyAdded();
/// @notice Thrown when trying to retrieve an aggchain verification key that does not exist.
error OwnedAggchainVKeyNotFound();
/// @notice Thrown when trying to initialize the incorrect initialize function.
error InvalidInitializeFunction();
/// @notice Thrown when trying to enable the default vkeys when it is already enabled.
error UseDefaultVkeysAlreadyEnabled();
/// @notice Thrown when trying to disable the default vkeys when it is already disabled.
error UseDefaultVkeysAlreadyDisabled();
/// @notice Thrown when trying to enable the default signers when it is already enabled.
error UseDefaultSignersAlreadyEnabled();
/// @notice Thrown when trying to disable the default signers when it is already disabled.
error UseDefaultSignersAlreadyDisabled();
/// @notice Thrown when trying to retrieve an aggchain verification key from the mapping that doesn't exists.
error AggchainVKeyNotFound();
/// @notice Thrown when trying to set the aggchain manager to zero address.
error AggchainManagerCannotBeZero();
/// @notice Thrown when the aggchain manager is already initialized.
error AggchainManagerAlreadyInitialized();
/// @notice Thrown when an invalid initial aggchain vkey is provided.
error InvalidInitAggchainVKey();
/// @notice Thrown when trying to use default signers but also providing signers to add
error ConflictingDefaultSignersConfiguration();
/// @notice Thrown when the caller is not the aggchain manager
error OnlyAggchainManager();
/// @notice Thrown when the caller is not the pending aggchain manager
error OnlyPendingAggchainManager();
/// @notice Thrown when trying to call a function with an input zero address
error InvalidZeroAddress();
/// @notice Thrown when the aggchainData has an invalid format
error InvalidAggchainDataLength();
/// @notice Thrown when the aggchainvKeySelector contains an invalid aggchain type.
error InvalidAggchainType();
/// @notice Thrown when threshold is zero, greater than the number of aggchainSigners.
error InvalidThreshold();
/// @notice Thrown when trying to add a signer that already exists.
error SignerAlreadyExists();
/// @notice Thrown when trying to remove a signer that doesn't exist.
error SignerDoesNotExist();
/// @notice Thrown when trying to add a zero address as a signer.
error SignerCannotBeZero();
/// @notice Thrown when the aggchainSingers is greater than 255.
error AggchainSignersTooHigh();
/// @notice Thrown when trying to add a signer with an empty URL.
error SignerURLCannotBeEmpty();
/// @notice Thrown when the indices for signer removal are not in descending order.
error IndicesNotInDescendingOrder();
/// @notice Thrown when trying to compute the aggchain hash without initializing the signers hash.
error AggchainSignersHashNotInitialized();
/// @notice Thrown when the keys and values arrays have different lengths in batch metadata operations.
error MetadataArrayLengthMismatch();
/// @notice Thrown when the caller is not the aggchain metadata manager
error OnlyAggchainMetadataManager();
}
/**
* @title IAggchainBase
* @notice Core interface for aggchain implementations
* @dev All aggchain contracts must implement these functions for integration with the rollup manager.
* Different implementations (FEP, ECDSA) may handle these functions differently based on their consensus mechanism.
*/
interface IAggchainBase is
IAggchainBaseErrors,
IAggchainBaseEvents,
IAggchainSigners
{
/**
* @notice Gets aggchain hash for consensus verification
* @dev Each implementation computes this hash differently based on its consensus mechanism.
* The hash is used by the rollup manager to verify state transitions.
* @param aggchainData Custom chain data to build the consensus hash
* @return The computed aggchain hash for verification
*/
function getAggchainHash(
bytes calldata aggchainData
) external view returns (bytes32);
/**
* @notice Callback from the AgglayerManager after successful pessimistic proof verification
* @dev Each implementation handles state updates differently
* @param aggchainData Custom chain data containing state update information
*/
function onVerifyPessimistic(bytes calldata aggchainData) external;
/**
* @notice Sets the initial aggchain manager during contract deployment
* @dev Can only be called once by the rollup manager during initialization.
* The aggchain manager has privileged access to modify consensus parameters.
* @param newAggchainManager The address of the new aggchain manager
*/
function initAggchainManager(address newAggchainManager) external;
/// @notice Returns the unique aggchain type identifier.
function AGGCHAIN_TYPE() external view returns (bytes2);
/**
* @notice Returns the current aggchain manager address
* @dev The aggchain manager has administrative privileges over consensus parameters
* @return The address of the current aggchain manager
*/
function aggchainManager() external view returns (address);
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.28;
/**
* @title IAggchainSigners
* @notice Interface for multisig signer management functionality
* @dev This interface is implemented by both AggchainBase contracts and AgglayerGateway,
* providing a unified way to manage signers for consensus verification.
* Implementations may use local storage or delegate to a gateway contract.
*/
interface IAggchainSigners {
////////////////////////////////////////////////////////////
// Structs //
////////////////////////////////////////////////////////////
/**
* @notice Struct to hold signer information
* @param addr The address of the signer
* @param url The URL associated with the signer
*/
struct SignerInfo {
address addr;
string url;
}
/**
* @notice Struct to hold information for removing a signer
* @param addr The address of the signer to remove
* @param index The index of the signer in the aggchainSigners array
*/
struct RemoveSignerInfo {
address addr;
uint256 index;
}
/**
* @notice Emitted when signers and threshold are updated in a batch operation.
* @param aggchainSigners The updated array of signer addresses.
* @param newThreshold The new threshold value.
* @param newAggchainMultisigHash The new hash of the aggchainMultisig configuration.
*/
event SignersAndThresholdUpdated(
address[] aggchainSigners,
uint256 newThreshold,
bytes32 newAggchainMultisigHash
);
////////////////////////////////////////////////////////////
// View Functions //
////////////////////////////////////////////////////////////
/**
* @notice Check if an address is a signer
* @param _signer Address to check
* @return True if the address is a signer
*/
function isSigner(address _signer) external view returns (bool);
/**
* @notice Get the minimum number of signatures required for consensus
* @dev Returns the threshold value for multisig validation
* @return threshold Minimum number of signatures required
*/
function getThreshold() external view returns (uint256);
/**
* @notice Get the total number of registered signers
* @dev Returns the count of active signers in the multisig
* @return count Total number of aggchainSigners currently registered
*/
function getAggchainSignersCount() external view returns (uint256);
/**
* @notice Get all registered signer addresses
* @dev Returns the complete list of active signers
* @return signers Array containing all signer addresses
*/
function getAggchainSigners() external view returns (address[] memory);
/**
* @notice Returns the hash of current multisig configuration
* @dev Computed as keccak256(abi.encodePacked(threshold, aggchainSigners)).
* Used by aggchain contracts for efficient consensus verification.
* @return multisigHash The current aggchainMultisigHash for validation
*/
function getAggchainMultisigHash() external view returns (bytes32);
/**
* @notice Get detailed information for all registered signers
* @dev Returns both addresses and associated URLs/endpoints for each signer
* @return signerInfos Array of SignerInfo structs containing complete signer details
*/
function getAggchainSignerInfos()
external
view
returns (SignerInfo[] memory);
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
import "./IBaseLegacyAgglayerGER.sol";
interface IAgglayerBridge {
/**
* @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 amount of the permit does not match
*/
error NotValidAmount();
/**
* @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 proxy deployment fails
*/
error FailedProxyDeployment();
/**
* @dev Thrown when try to set a zero address to a non valid zero address field
*/
error InvalidZeroAddress();
/**
* @dev Thrown when sender is not the proxied tokens manager
*/
error OnlyProxiedTokensManager();
/**
* @dev Thrown when trying to call a function that only the pending ProxiedTokensManager can call.
*/
error OnlyPendingProxiedTokensManager();
/**
* @dev Thrown when trying to set bridgeAddress to as proxied tokens manager role.
*/
error BridgeAddressNotAllowed();
/**
* @dev Thrown when trying to initialize the incorrect initialize function
*/
error InvalidInitializeFunction();
/**
* @dev Thrown when failing to retrieve the owner from proxyAdmin
*/
error InvalidProxyAdmin(address proxyAdmin);
/**
* @dev Thrown when the owner of a proxyAdmin is zero address
*/
error InvalidZeroProxyAdminOwner(address proxyAdmin);
/**
* @dev Thrown when the global index has any unused bits set to 1
*/
error InvalidGlobalIndex();
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,
IBaseLegacyAgglayerGER _globalExitRootManager,
address _polygonRollupManager,
bytes memory _gasTokenMetadata
) external;
function getTokenMetadata(
address token
) external view returns (bytes memory);
function getWrappedTokenBridgeImplementation()
external
view
returns (address);
function getProxiedTokensManager() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import "./IAggchainSigners.sol";
// based on: https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/ISP1VerifierGateway.sol
interface IAgglayerGatewayEvents {
/// @notice Emitted when a verifier route is added.
/// @param selector The verifier selector that was added.
/// @param verifier The address of the verifier contract.
/// @param pessimisticVKey The verification key
event RouteAdded(
bytes4 selector,
address verifier,
bytes32 pessimisticVKey
);
/// @notice Emitted when a verifier route is frozen.
/// @param selector The verifier selector that was frozen.
/// @param verifier The address of the verifier contract.
event RouteFrozen(
bytes4 selector,
address verifier,
bytes32 pessimisticVKey
);
/**
* Emitted when a new default aggchain verification key is added
* @param selector The 4 bytes selector of the added default aggchain verification key.
* @param newVKey New aggchain verification key to be added
*/
event AddDefaultAggchainVKey(bytes4 selector, bytes32 newVKey);
/**
* Emitted when a default aggchain verification key is update
* @param selector The 4 bytes selector of the updated default aggchain verification key.
* @param previousVKey Aggchain verification key previous value
* @param newVKey Aggchain verification key updated value
*/
event UpdateDefaultAggchainVKey(
bytes4 selector,
bytes32 previousVKey,
bytes32 newVKey
);
/**
* Emitted when a default aggchain verification key is set to zero
* @param selector The 4 bytes selector of the updated default aggchain verification key.
*/
event UnsetDefaultAggchainVKey(bytes4 selector);
}
/// @dev Extended error events from https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/ISP1VerifierGateway.sol
interface IAgglayerGatewayErrors {
/// @notice Thrown when the verifier route is not found.
/// @param selector The verifier selector that was specified.
error RouteNotFound(bytes4 selector);
/// @notice Thrown when the verifier route is found, but is frozen.
/// @param selector The verifier selector that was specified.
error RouteIsFrozen(bytes4 selector);
/// @notice Thrown when trying to freeze a route that is already frozen.
/// @param selector The pessimistic verification key selector that was specified.
error RouteIsAlreadyFrozen(bytes4 selector);
/// @notice Thrown when adding a verifier route and the selector already contains a route.
/// @param selector The pessimistic verification key selector that was specified.
/// @param verifier The address of the verifier contract in the existing route.
error RouteAlreadyExists(bytes4 selector, address verifier);
/// @notice Thrown when adding a verifier route and the selector returned by the verifier is
/// zero.
error PPSelectorCannotBeZero();
/// @notice Thrown when adding a verifier key with value zero
error VKeyCannotBeZero();
/// @notice Thrown when the caller is not the AggLayerAdmin
error OnlyAggLayerAdmin();
//// @notice Thrown when the caller is not the pending AggLayerAdmin
error OnlyPendingAggLayerAdmin();
/// @notice Thrown when trying to add an aggchain verification key that already exists
error AggchainVKeyAlreadyExists();
/// @notice Thrown when trying to retrieve an aggchain verification key from the mapping that doesn't exists
error AggchainVKeyNotFound();
/// @notice Thrown when trying to call a function with an input zero address
error InvalidZeroAddress();
/// @notice Thrown when trying to call a function with an invalid initializer version
error InvalidInitializer();
/// @notice Thrown when the input proof bytes are invalid.
error InvalidProofBytesLength();
/// @notice Thrown when the aggchain signers hash has not been initialized
error AggchainSignersHashNotInitialized();
/// @notice Thrown when indices for signer removal are not in descending order
error IndicesNotInDescendingOrder();
/// @notice Thrown when trying to set more than 255 signers
error AggchainSignersTooHigh();
/// @notice Thrown when the threshold exceeds the number of signers
error InvalidThreshold();
/// @notice Thrown when trying to add a zero address as signer
error SignerCannotBeZero();
/// @notice Thrown when trying to add a signer with empty URL
error SignerURLCannotBeEmpty();
/// @notice Thrown when trying to add a signer that already exists
error SignerAlreadyExists();
/// @notice Thrown when trying to remove a signer that doesn't exist
error SignerDoesNotExist();
}
/// @title IAgglayerGateway
/// @notice This contract is the interface for the AgglayerGateway.
/// @notice Based on https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/ISP1VerifierGateway.sol
interface IAgglayerGateway is
IAgglayerGatewayEvents,
IAgglayerGatewayErrors,
IAggchainSigners
{
/**
* Struct that defines a verifier route
* @param verifier The address of the verifier contract.
* @param pessimisticVKey The verification key to be used for verifying pessimistic proofs.
* @param frozen Whether the route is frozen.
*/
struct AggLayerVerifierRoute {
address verifier; // SP1 Verifier. It contains sanity check SP1 version with the 4 first bytes of the proof. proof[4:]
bytes32 pessimisticVKey;
bool frozen;
}
/**
* @notice returns the current aggchain verification key, used to verify chain's FEP.
* @dev This function is necessary to query the map from an external function. In solidity maps are not
* directly accessible from external functions like other state variables.
*/
function getDefaultAggchainVKey(
bytes4 defaultAggchainSelector
) external view returns (bytes32);
/// @notice Verifies a pessimistic proof with given public values and proof.
/// @dev It is expected that the first 4 bytes of proofBytes must match the first 4 bytes of
/// target verifier's VERIFIER_HASH.
/// @param publicValues The public values encoded as bytes.
/// @param proofBytes The proof of the program execution the SP1 zkVM encoded as bytes.
function verifyPessimisticProof(
bytes calldata publicValues,
bytes calldata proofBytes
) external view;
/// @notice Adds a verifier route. This enable proofs to be routed to this verifier.
/// @dev Only callable by the owner. The owner is responsible for ensuring that the specified
/// verifier is correct with a valid VERIFIER_HASH. Once a route to a verifier is added, it
/// cannot be removed.
/// @param pessimisticVKeySelector The verifier selector to add.
/// @param verifier The address of the verifier contract. This verifier MUST implement the
/// ISP1VerifierWithHash interface.
/// @param pessimisticVKey The verification key to be used for verifying pessimistic proofs.
function addPessimisticVKeyRoute(
bytes4 pessimisticVKeySelector,
address verifier,
bytes32 pessimisticVKey
) external;
/// @notice Freezes a verifier route. This prevents proofs from being routed to this verifier.
/// @dev Only callable by the owner. Once a route to a verifier is frozen, it cannot be
/// unfrozen.
/// @param pessimisticVKeySelector The verifier selector to freeze.
function freezePessimisticVKeyRoute(
bytes4 pessimisticVKeySelector
) external;
////////////////////////////////////////////////////////////
// Multisig Functions //
////////////////////////////////////////////////////////////
/**
* @notice Updates signers and threshold for multisig operations
* @dev Removes signers first (in descending index order), then adds new signers, then updates threshold
* @param _signersToRemove Array of signers to remove with their indices (MUST be in descending index order)
* @param _signersToAdd Array of new signers to add with their URLs
* @param _newThreshold New threshold value
*/
function updateSignersAndThreshold(
RemoveSignerInfo[] memory _signersToRemove,
SignerInfo[] memory _signersToAdd,
uint256 _newThreshold
) external;
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
import "./IBaseLegacyAgglayerGER.sol";
interface IAgglayerGER is IBaseLegacyAgglayerGER {
function getLastGlobalExitRoot() external view returns (bytes32);
function getRoot() external view returns (bytes32);
function l1InfoRootMap(uint32 depositCount) external view returns (bytes32);
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
import "./IVerifierRollup.sol";
import "./IPolygonRollupBase.sol";
import {ITransparentUpgradeableProxy} from "@openzeppelin/contracts5/proxy/transparent/TransparentUpgradeableProxy.sol";
interface IAgglayerManager {
/**
* @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 upgrade a rollup a sender that's not the aggchain manager
*/
error OnlyAggchainManager();
/**
* @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();
/**
* @dev Invalid Rollup type parameters
*/
error InvalidRollupType();
/**
* @dev Invalid Rollup parameters
*/
error InvalidRollup();
/**
* @dev Not valid L1 info tree leaf count
*/
error L1InfoTreeLeafCountInvalid();
/**
* @dev Only State Transition Chains
*/
error OnlyStateTransitionChains();
/**
* @dev Pending state num exist
*/
error PendingStateNumExist();
/**
* @dev Thrown when a function is executed for a State transition chains when it is not allowed
* @dev This function was previously called `OnlyChainsWithPessimisticProofs`but with the new ALGateway verifier Type
* state transitions must be excluded
*/
error StateTransitionChainsNotAllowed();
/**
* @dev Custom chain data must be zero for pessimistic verifier type
*/
error AggchainDataMustBeZeroForPessimisticVerifierType();
/**
* @dev Invalid Pessimistic proof
*/
error InvalidPessimisticProof();
/**
* @dev Invalid Verifier Type when getting rollup data
*/
error InvalidVerifierType();
/**
* @dev Thrown when trying to deploy rollup Manager with some zero address as the input
*/
error InvalidConstructorInputs();
/**
* @dev Thrown when trying to create a rollup but the input parameters are not according with the chosen rollupType
*/
error InvalidInputsForRollupType();
/**
* @dev Thrown when trying to add an existing rollup or create a new rollup type with an invalid consensus implementation address
*/
error InvalidImplementationAddress();
/**
* @dev Thrown when trying to create rollup or rollup type with an invalid verifier address
*/
error InvalidVerifierAddress();
/**
* @dev Thrown when trying to migrate a rollup to a non pessimistic rollup type with `initMigration` function.
*/
error NewRollupTypeMustBePessimisticOrALGateway();
/**
* @dev Thrown when trying to finish a migration of a rollup to a pessimistic rollup type with `verifyPessimisticTrustedAggregator` function and the proposed new local exit root does not match the expected new local exit root
*/
error InvalidNewLocalExitRoot();
enum VerifierType {
StateTransition,
Pessimistic,
ALGateway
}
function addNewRollupType(
address consensusImplementation,
address verifier,
uint64 forkID,
VerifierType rollupVerifierType,
bytes32 initRoot,
string memory description,
bytes32 programVKey
) external;
function obsoleteRollupType(uint32 rollupTypeID) external;
function attachAggchainToAL(
uint32 rollupTypeID,
uint64 chainID,
bytes memory initializeBytesAggchain
) external;
function addExistingRollup(
address rollupAddress,
address verifier,
uint64 forkID,
uint64 chainID,
bytes32 initRoot,
VerifierType rollupVerifierType,
bytes32 programVKey,
bytes32 initPessimisticRoot
) external;
function updateRollupByRollupAdmin(
ITransparentUpgradeableProxy rollupContract,
uint32 newRollupTypeID
) external;
function updateRollup(
ITransparentUpgradeableProxy rollupContract,
uint32 newRollupTypeID,
bytes memory upgradeData
) external;
function rollbackBatches(
IPolygonRollupBase rollupContract,
uint64 targetBatch
) external;
function onSequenceBatches(
uint64 newSequencedBatches,
bytes32 newAccInputHash
) external returns (uint64);
function verifyBatchesTrustedAggregator(
uint32 rollupID,
uint64 pendingStateNum,
uint64 initNumBatch,
uint64 finalNewBatch,
bytes32 newLocalExitRoot,
bytes32 newStateRoot,
address beneficiary,
bytes32[24] calldata proof
) external;
function verifyPessimisticTrustedAggregator(
uint32 rollupID,
uint32 l1InfoTreeLeafCount,
bytes32 newLocalExitRoot,
bytes32 newPessimisticRoot,
bytes calldata proof,
bytes memory aggchainData
) external;
function activateEmergencyState() external;
function deactivateEmergencyState() external;
function setBatchFee(uint256 newBatchFee) external;
function getRollupExitRoot() external view returns (bytes32);
function getLastVerifiedBatch(
uint32 rollupID
) external view returns (uint64);
function calculateRewardPerBatch() external view returns (uint256);
function getBatchFee() external view returns (uint256);
function getForcedBatchFee() external view returns (uint256);
function getInputPessimisticBytes(
uint32 rollupID,
bytes32 selectedGlobalExitRoot,
bytes32 newLocalExitRoot,
bytes32 newPessimisticRoot,
bytes memory aggchainData
) external view returns (bytes memory);
function getInputSnarkBytes(
uint32 rollupID,
uint64 initNumBatch,
uint64 finalNewBatch,
bytes32 newLocalExitRoot,
bytes32 oldStateRoot,
bytes32 newStateRoot
) external view returns (bytes memory);
function getRollupBatchNumToStateRoot(
uint32 rollupID,
uint64 batchNum
) external view returns (bytes32);
function lastDeactivatedEmergencyStateTimestamp()
external
view
returns (uint64);
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
interface IBaseLegacyAgglayerGER {
/**
* @dev Thrown when the caller is not the allowed contracts
*/
error OnlyAllowedContracts();
/**
* @dev Thrown when the caller is not the coinbase neither the globalExitRootUpdater
*/
error OnlyGlobalExitRootUpdater();
/**
* @dev Thrown when trying to call a function that only the pending GlobalExitRootUpdater can call.
*/
error OnlyPendingGlobalExitRootUpdater();
/**
* @dev Thrown when the caller is not the globalExitRootRemover
*/
error OnlyGlobalExitRootRemover();
/**
* @dev Thrown when trying to call a function that only the pending GlobalExitRootRemover can call.
*/
error OnlyPendingGlobalExitRootRemover();
/**
* @dev Thrown when trying to insert a global exit root that is already set
*/
error GlobalExitRootAlreadySet();
/**
* @dev Thrown when trying to remove a ger that doesn't exist
*/
error GlobalExitRootNotFound();
/**
* @dev Thrown when trying to call a function with an input zero address
*/
error InvalidZeroAddress();
function updateExitRoot(bytes32 newRollupExitRoot) external;
function globalExitRootMap(
bytes32 globalExitRootNum
) external returns (uint256);
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
interface IEmergencyManager {
/**
* @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 Emitted when emergency state is activated
*/
event EmergencyStateActivated();
/**
* @dev Emitted when emergency state is deactivated
*/
event EmergencyStateDeactivated();
/**
* @notice Returns whether the emergency state is active
*/
function isEmergencyState() external view returns (bool);
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
interface IPolygonConsensusBase {
/**
* @dev Thrown when trying to set the admin to the zero address
*/
error AdminCannotBeZeroAddress();
function initialize(
address _admin,
address sequencer,
uint32 networkID,
address gasTokenAddress,
string memory sequencerURL,
string memory _networkName
) external;
function admin() external view returns (address);
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
interface IPolygonPessimisticConsensus {
function getConsensusHash() external view returns (bytes32);
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
import "./IPolygonConsensusBase.sol";
interface IPolygonRollupBase is IPolygonConsensusBase {
function onVerifyBatches(
uint64 lastVerifiedBatch,
bytes32 newStateRoot,
address aggregator
) external;
function rollbackBatches(
uint64 targetBatch,
bytes32 accInputHashToRollback
) external;
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
interface IPolygonZkEVMBridge {
/**
* @dev Thrown when sender is not the PolygonZkEVM address
*/
error OnlyPolygonZkEVM();
/**
* @dev Thrown when the destination network is invalid
*/
error DestinationNetworkInvalid();
/**
* @dev Thrown when the amount does not match msg.value
*/
error AmountDoesNotMatchMsgValue();
/**
* @dev Thrown when user is bridging tokens and is also sending a value
*/
error MsgValueNotZero();
/**
* @dev Thrown when the Ether transfer on claimAsset fails
*/
error EtherTransferFailed();
/**
* @dev Thrown when the message transaction on claimMessage fails
*/
error MessageFailed();
/**
* @dev Thrown when the global exit root does not exist
*/
error GlobalExitRootInvalid();
/**
* @dev Thrown when the smt proof does not match
*/
error InvalidSmtProof();
/**
* @dev Thrown when an index is already claimed
*/
error AlreadyClaimed();
/**
* @dev Thrown when the owner of permit does not match the sender
*/
error NotValidOwner();
/**
* @dev Thrown when the spender of the permit does not match this contract address
*/
error NotValidSpender();
/**
* @dev Thrown when the amount of the permit does not match
*/
error NotValidAmount();
/**
* @dev Thrown when the permit data contains an invalid signature
*/
error NotValidSignature();
function bridgeAsset(
uint32 destinationNetwork,
address destinationAddress,
uint256 amount,
address token,
bool forceUpdateGlobalExitRoot,
bytes calldata permitData
) external payable;
function bridgeMessage(
uint32 destinationNetwork,
address destinationAddress,
bool forceUpdateGlobalExitRoot,
bytes calldata metadata
) external payable;
function claimAsset(
bytes32[32] calldata smtProof,
uint32 index,
bytes32 mainnetExitRoot,
bytes32 rollupExitRoot,
uint32 originNetwork,
address originTokenAddress,
uint32 destinationNetwork,
address destinationAddress,
uint256 amount,
bytes calldata metadata
) external;
function claimMessage(
bytes32[32] calldata smtProof,
uint32 index,
bytes32 mainnetExitRoot,
bytes32 rollupExitRoot,
uint32 originNetwork,
address originAddress,
uint32 destinationNetwork,
address destinationAddress,
uint256 amount,
bytes calldata metadata
) external;
function updateGlobalExitRoot() external;
function activateEmergencyState() external;
function deactivateEmergencyState() external;
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
interface IPolygonZkEVMErrors {
/**
* @dev Thrown when the pending state timeout exceeds the _HALT_AGGREGATION_TIMEOUT
*/
error PendingStateTimeoutExceedHaltAggregationTimeout();
/**
* @dev Thrown when the trusted aggregator timeout exceeds the _HALT_AGGREGATION_TIMEOUT
*/
error TrustedAggregatorTimeoutExceedHaltAggregationTimeout();
/**
* @dev Thrown when the caller is not the admin
*/
error OnlyAdmin();
/**
* @dev Thrown when the caller is not the trusted sequencer
*/
error OnlyTrustedSequencer();
/**
* @dev Thrown when the caller is not the trusted aggregator
*/
error OnlyTrustedAggregator();
/**
* @dev Thrown when attempting to sequence 0 batches
*/
error SequenceZeroBatches();
/**
* @dev Thrown when attempting to sequence or verify more batches than _MAX_VERIFY_BATCHES
*/
error ExceedMaxVerifyBatches();
/**
* @dev Thrown when the forced data does not match
*/
error ForcedDataDoesNotMatch();
/**
* @dev Thrown when the sequenced timestamp is below the forced minimum timestamp
*/
error SequencedTimestampBelowForcedTimestamp();
/**
* @dev Thrown when a global exit root is not zero and does not exist
*/
error GlobalExitRootNotExist();
/**
* @dev Thrown when transactions array length is above _MAX_TRANSACTIONS_BYTE_LENGTH.
*/
error TransactionsLengthAboveMax();
/**
* @dev Thrown when a sequenced timestamp is not inside a correct range.
*/
error SequencedTimestampInvalid();
/**
* @dev Thrown when there are more sequenced force batches than were actually submitted, should be unreachable
*/
error ForceBatchesOverflow();
/**
* @dev Thrown when there are more sequenced force batches than were actually submitted
*/
error TrustedAggregatorTimeoutNotExpired();
/**
* @dev Thrown when attempting to access a pending state that does not exist
*/
error PendingStateDoesNotExist();
/**
* @dev Thrown when the init num batch does not match with the one in the pending state
*/
error InitNumBatchDoesNotMatchPendingState();
/**
* @dev Thrown when the old state root of a certain batch does not exist
*/
error OldStateRootDoesNotExist();
/**
* @dev Thrown when the init verification batch is above the last verification batch
*/
error InitNumBatchAboveLastVerifiedBatch();
/**
* @dev Thrown when the final verification batch is below or equal the last verification batch
*/
error FinalNumBatchBelowLastVerifiedBatch();
/**
* @dev Thrown when the zkproof is not valid
*/
error InvalidProof();
/**
* @dev Thrown when attempting to consolidate a pending state not yet consolidable
*/
error PendingStateNotConsolidable();
/**
* @dev Thrown when attempting to consolidate a pending state that is already consolidated or does not exist
*/
error PendingStateInvalid();
/**
* @dev Thrown when the matic amount is below the necessary matic fee
*/
error NotEnoughMaticAmount();
/**
* @dev Thrown when attempting to sequence a force batch using sequenceForceBatches and the
* force timeout did not expire
*/
error ForceBatchTimeoutNotExpired();
/**
* @dev Thrown when attempting to set a new trusted aggregator timeout equal or bigger than current one
*/
error NewTrustedAggregatorTimeoutMustBeLower();
/**
* @dev Thrown when attempting to set a new pending state timeout equal or bigger than current one
*/
error NewPendingStateTimeoutMustBeLower();
/**
* @dev Thrown when attempting to set a new multiplier batch fee in a invalid range of values
*/
error InvalidRangeMultiplierBatchFee();
/**
* @dev Thrown when attempting to set a batch time target in an invalid range of values
*/
error InvalidRangeBatchTimeTarget();
/**
* @dev Thrown when attempting to set a force batch timeout in an invalid range of values
*/
error InvalidRangeForceBatchTimeout();
/**
* @dev Thrown when the caller is not the pending admin
*/
error OnlyPendingAdmin();
/**
* @dev Thrown when the final pending state num is not in a valid range
*/
error FinalPendingStateNumInvalid();
/**
* @dev Thrown when the final num batch does not match with the one in the pending state
*/
error FinalNumBatchDoesNotMatchPendingState();
/**
* @dev Thrown when the stored root matches the new root proving a different state
*/
error StoredRootMustBeDifferentThanNewRoot();
/**
* @dev Thrown when the batch is already verified when attempting to activate the emergency state
*/
error BatchAlreadyVerified();
/**
* @dev Thrown when the batch is not sequenced or not at the end of a sequence when attempting to activate the emergency state
*/
error BatchNotSequencedOrNotSequenceEnd();
/**
* @dev Thrown when the halt timeout is not expired when attempting to activate the emergency state
*/
error HaltTimeoutNotExpired();
/**
* @dev Thrown when the old accumulate input hash does not exist
*/
error OldAccInputHashDoesNotExist();
/**
* @dev Thrown when the new accumulate input hash does not exist
*/
error NewAccInputHashDoesNotExist();
/**
* @dev Thrown when the new state root is not inside prime
*/
error NewStateRootNotInsidePrime();
/**
* @dev Thrown when force batch is not allowed
*/
error ForceBatchNotAllowed();
/**
* @dev Thrown when try to activate force batches when they are already active
*/
error ForceBatchesAlreadyActive();
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
import "./IPolygonZkEVMErrors.sol";
interface IPolygonZkEVMEtrogErrors 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();
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// imported from: https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/ISP1Verifier.sol
/// @title SP1 Verifier Interface
/// @author Succinct Labs
/// @notice This contract is the interface for the SP1 Verifier.
interface ISP1Verifier {
/// @notice Verifies a proof with given public values and vkey.
/// @dev It is expected that the first 4 bytes of proofBytes must match the first 4 bytes of
/// target verifier's VERIFIER_HASH.
/// @param programVKey The verification key for the RISC-V program.
/// @param publicValues The public values encoded as bytes.
/// @param proofBytes The proof of the program execution the SP1 zkVM encoded as bytes.
function verifyProof(
bytes32 programVKey,
bytes calldata publicValues,
bytes calldata proofBytes
) external view;
}
interface ISP1VerifierWithHash is ISP1Verifier {
/// @notice Returns the hash of the verifier.
function VERIFIER_HASH() external pure returns (bytes32);
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
/**
* @dev Define interface verifier
*/
interface IVerifierRollup {
function verifyProof(
bytes32[24] calldata proof,
uint256[1] calldata pubSignals
) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
interface IVersion {
function version() external pure returns (string memory);
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.28;
import "@openzeppelin/contracts-upgradeable4/proxy/utils/Initializable.sol";
import "./PolygonConsensusBase.sol";
import "../interfaces/IAgglayerGateway.sol";
import "../interfaces/IAggchainBase.sol";
import "../interfaces/IVersion.sol";
/**
* @title AggchainBase
* @notice Base contract for aggchain implementations. This contract is imported by other aggchain implementations to reuse the common logic.
*/
abstract contract AggchainBase is
PolygonConsensusBase,
IAggchainBase,
IVersion
{
////////////////////////////////////////////////////////////
// Constants & Immutables //
////////////////////////////////////////////////////////////
// Consensus type that supports generic aggchain hash
// Naming has been kept as CONSENSUS_TYPE for consistency with the previous consensus type (PolygonPessimisticConsensus.sol)
uint32 public constant CONSENSUS_TYPE = 1;
// Maximum number of aggchain signers supported
uint256 public constant MAX_AGGCHAIN_SIGNERS = 255;
// AgglayerGateway address, used in case the flag `useDefaultGateway` is set to true, the aggchains keys are managed by the gateway
IAgglayerGateway public immutable aggLayerGateway;
////////////////////////////////////////////////////////////
// Variables //
////////////////////////////////////////////////////////////
// Added legacy storage values to avoid storage collision with PolygonValidiumEtrog contract in case this consensus contract is upgraded to aggchain
address private _legacyDataAvailabilityProtocol;
bool private _legacyIsSequenceWithDataAvailabilityAllowed;
// Added legacy storage values from previous aggchainBase
/// @custom:oz-renamed-from vKeyManager
address public _legacyvKeyManager;
/// @custom:oz-renamed-from pendingVKeyManager
address public _legacypendingVKeyManager;
// Flag to enable/disable the use of the default verification keys from the gateway
/// @custom:oz-renamed-from useDefaultGateway
bool public useDefaultVkeys;
// Flag to enable or disable the use of default signers from the gateway.
// Introduced in this version of the contract. This variable is packed into
// the same storage slot as `useDefaultVkeys`, so there is no risk of storage
// layout collision with previous versions.
bool public useDefaultSigners;
/// @notice Address that manages all the functionalities related to the aggchain
address public aggchainManager;
/// @notice This account will be able to accept the aggchainManager role
address public pendingAggchainManager;
////////////////////////////////////////////////////////////
// Mappings //
////////////////////////////////////////////////////////////
// AggchainVKeys mapping
mapping(bytes4 aggchainVKeySelector => bytes32 ownedAggchainVKey)
public ownedAggchainVKeys;
////////////////////////////////////////////////////////////
// Multisig //
////////////////////////////////////////////////////////////
/// @notice Array of multisig aggchainSigners
address[] public aggchainSigners;
/// @notice Mapping that stores the URL of each signer
/// It's used as well to check if an address is a signer
mapping(address => string) public signerToURLs;
/// @notice Threshold required for multisig operations
uint256 public threshold;
/// @notice Hash of the current multisig configuration.
/// @dev Computed as keccak256(abi.encodePacked(threshold, aggchainSigners))
bytes32 public aggchainMultisigHash;
////////////////////////////////////////////////////////////
// Metadata //
////////////////////////////////////////////////////////////
/// @notice Address that manages the metadata functionality
address public aggchainMetadataManager;
/// @notice Optional mapping to store metadata for the aggchain
mapping(string => string) public aggchainMetadata;
/**
* @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.
*/
/// @custom:oz-renamed-from _gap
uint256[44] private __gap;
////////////////////////////////////////////////////////////
// Modifiers //
////////////////////////////////////////////////////////////
/// @dev Only allows a function to be callable if the message sender is the aggchain manager
modifier onlyAggchainManager() {
if (aggchainManager != msg.sender) {
revert OnlyAggchainManager();
}
_;
}
/// @dev Only allows a function to be callable if the message sender is the aggchain metadata manager
modifier onlyAggchainMetadataManager() {
if (aggchainMetadataManager != msg.sender) {
revert OnlyAggchainMetadataManager();
}
_;
}
////////////////////////////////////////////////////////////
// Constructor //
////////////////////////////////////////////////////////////
/**
* @param _globalExitRootManager Global exit root manager address.
* @param _pol POL token address.
* @param _bridgeAddress Bridge address.
* @param _rollupManager Rollup manager address.
* @param _aggLayerGateway AgglayerGateway address.
*/
constructor(
IAgglayerGER _globalExitRootManager,
IERC20Upgradeable _pol,
IAgglayerBridge _bridgeAddress,
AgglayerManager _rollupManager,
IAgglayerGateway _aggLayerGateway
)
PolygonConsensusBase(
_globalExitRootManager,
_pol,
_bridgeAddress,
_rollupManager
)
{
// Check if the gateway address is valid
if (
address(_aggLayerGateway) == address(0) ||
address(_globalExitRootManager) == address(0) ||
address(_pol) == address(0) ||
address(_bridgeAddress) == address(0) ||
address(_rollupManager) == address(0)
) {
revert InvalidZeroAddress();
}
aggLayerGateway = _aggLayerGateway;
}
////////////////////////////////////////////////////////////
// Initialization //
////////////////////////////////////////////////////////////
/**
* @notice Sets the aggchain manager
* @dev Can only be called by the rollup manager during initialization
* @param newAggchainManager The address of the new aggchain manager
*/
function initAggchainManager(
address newAggchainManager
) external onlyRollupManager {
// Can only be initialized if current aggchainmanger is zero
if (aggchainManager != address(0)) {
revert AggchainManagerAlreadyInitialized();
}
if (newAggchainManager == address(0)) {
revert AggchainManagerCannotBeZero();
}
aggchainManager = newAggchainManager;
emit AcceptAggchainManagerRole(address(0), aggchainManager);
}
/**
* @notice Initializer AggchainBase storage
* @param _admin Admin address
* @param sequencer Trusted sequencer address
* @param _gasTokenAddress Indicates the token address in mainnet that will be used as a gas token
* @dev 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
* @param _useDefaultVkeys Flag to use default verification keys from gateway
* @param _useDefaultSigners Flag to use default signers from gateway
* @param _initOwnedAggchainVKey Initial owned aggchain verification key
* @param _initAggchainVKeySelector Initial aggchain selector
*/
function _initializeAggchainBaseAndConsensusBase(
address _admin,
address sequencer,
address _gasTokenAddress,
string memory sequencerURL,
string memory _networkName,
bool _useDefaultVkeys,
bool _useDefaultSigners,
bytes32 _initOwnedAggchainVKey,
bytes4 _initAggchainVKeySelector
) internal onlyInitializing {
if (address(_admin) == address(0) || address(sequencer) == address(0)) {
revert InvalidZeroAddress();
}
// Initialize PolygonConsensusBase
_initializePolygonConsensusBase(
_admin,
sequencer,
_gasTokenAddress,
sequencerURL,
_networkName
);
_initializeAggchainBase(
_useDefaultVkeys,
_useDefaultSigners,
_initOwnedAggchainVKey,
_initAggchainVKeySelector
);
}
/**
* @notice Initializer AggchainBase storage
* @param _useDefaultVkeys Flag to use default verification keys from gateway
* @param _useDefaultSigners Flag to use default signers from gateway
* @param _initOwnedAggchainVKey Initial owned aggchain verification key
* @param _initAggchainVKeySelector Initial aggchain selector
*/
function _initializeAggchainBase(
bool _useDefaultVkeys,
bool _useDefaultSigners,
bytes32 _initOwnedAggchainVKey,
bytes4 _initAggchainVKeySelector
) internal onlyInitializing {
useDefaultVkeys = _useDefaultVkeys;
useDefaultSigners = _useDefaultSigners;
// set the initial aggchain keys
ownedAggchainVKeys[_initAggchainVKeySelector] = _initOwnedAggchainVKey;
}
/**
* @notice Override the function to prevent the contract from being initialized with the initializer implemented at PolygonConsensusBase.
* @dev removing this function can cause critical security issues.
*/
function initialize(
address, // _admin
address, // sequencer
uint32, //networkID,
address, // _gasTokenAddress,
string memory, // sequencerURL,
string memory // _networkName
) external pure override(PolygonConsensusBase) {
// Set initialize variables
revert InvalidInitializeFunction();
}
///////////////////////////////////////////////
// Virtual functions //
///////////////////////////////////////////////
/**
* @notice Abstract function to extract aggchain parameters and verification key from aggchain data
* @dev This function must be implemented by the inheriting contract
* @param aggchainData Custom bytes provided by the chain containing the aggchain data
* @return aggchainVKey The extracted aggchain verification key
* @return aggchainParams The extracted aggchain parameters
*/
function getVKeyAndAggchainParams(
bytes memory aggchainData
) public view virtual returns (bytes32, bytes32);
///////////////////////////////////////////////
// Rollup manager callback functions //
///////////////////////////////////////////////
/**
* @notice Callback while pessimistic proof is being verified from the rollup manager
*
* aggchain_hash:
* Field: | CONSENSUS_TYPE | aggchain_vkey | aggchain_params | multisig_hash |
* length (bits): | 32 | 256 | 256 | 256 |
*
* @dev Returns the aggchain hash for a given aggchain data
* @param aggchainData Custom bytes provided by the chain containing the aggchain data
* @return aggchainHash resulting aggchain hash
*/
function getAggchainHash(
bytes memory aggchainData
) external view returns (bytes32) {
// Get signers hash from gateway if using default signers, otherwise use local storage
bytes32 cachedMultisigHash = getAggchainMultisigHash();
(
bytes32 aggchainVKey,
bytes32 aggchainParams
) = getVKeyAndAggchainParams(aggchainData);
return
keccak256(
abi.encodePacked(
CONSENSUS_TYPE,
aggchainVKey,
aggchainParams,
cachedMultisigHash
)
);
}
///////////////////////////////////////////////
// aggchainManager functions //
///////////////////////////////////////////////
/**
* @notice Updates signers and threshold for multisig operations
* @dev External wrapper for _updateSignersAndThreshold, restricted to aggchainManager
* @param _signersToRemove Array of signers to remove with their indices
* @param _signersToAdd Array of new signers to add with their URLs
* @param _newThreshold New threshold value for multisig operations
*/
function updateSignersAndThreshold(
RemoveSignerInfo[] memory _signersToRemove,
SignerInfo[] memory _signersToAdd,
uint256 _newThreshold
) external onlyAggchainManager {
_updateSignersAndThreshold(
_signersToRemove,
_signersToAdd,
_newThreshold
);
}
/**
* @notice Batch update signers and threshold in a single transaction
* @dev Removes signers first (in descending index order), then adds new signers, then updates threshold
* @param _signersToRemove Array of signers to remove with their indices (MUST be in descending index order)
* @param _signersToAdd Array of new signers to add with their URLs
* @param _newThreshold New threshold value
*/
function _updateSignersAndThreshold(
RemoveSignerInfo[] memory _signersToRemove,
SignerInfo[] memory _signersToAdd,
uint256 _newThreshold
) internal {
// Validate descending order of indices for removal to avoid index shifting issues
// When removing multiple signers, we must process them from highest index to lowest
if (_signersToRemove.length > 1) {
for (uint256 i = 0; i < _signersToRemove.length - 1; i++) {
if (
_signersToRemove[i].index <= _signersToRemove[i + 1].index
) {
revert IndicesNotInDescendingOrder();
}
}
}
// Remove signers (in descending index order to avoid index shifting issues)
for (uint256 i = 0; i < _signersToRemove.length; i++) {
_removeSignerInternal(
_signersToRemove[i].addr,
_signersToRemove[i].index
);
}
// Add new signers
for (uint256 i = 0; i < _signersToAdd.length; i++) {
_addSignerInternal(_signersToAdd[i].addr, _signersToAdd[i].url);
}
if (aggchainSigners.length > MAX_AGGCHAIN_SIGNERS) {
revert AggchainSignersTooHigh();
}
if (
_newThreshold > aggchainSigners.length ||
(aggchainSigners.length != 0 && _newThreshold == 0)
) {
revert InvalidThreshold();
}
threshold = _newThreshold;
// Update the signers hash once after all operations
_updateAggchainMultisigHash();
}
/**
* @notice Starts the aggchainManager role transfer
* @dev This is a two step process, the pending aggchainManager must accept to finalize the process
* @param newAggchainManager Address of the new aggchainManager
*/
function transferAggchainManagerRole(
address newAggchainManager
) external onlyAggchainManager {
if (newAggchainManager == address(0)) {
revert InvalidZeroAddress();
}
pendingAggchainManager = newAggchainManager;
emit TransferAggchainManagerRole(aggchainManager, newAggchainManager);
}
/**
* @notice Allow the current pending aggchainManager to accept the aggchainManager role
* @dev Can only be called by the pending aggchainManager
*/
function acceptAggchainManagerRole() external {
if (pendingAggchainManager != msg.sender) {
revert OnlyPendingAggchainManager();
}
address oldAggchainManager = aggchainManager;
aggchainManager = pendingAggchainManager;
delete pendingAggchainManager;
emit AcceptAggchainManagerRole(oldAggchainManager, aggchainManager);
}
/**
* @notice Sets the aggchain metadata manager
* @dev Can only be called by the aggchain manager
* @param newAggchainMetadataManager Address of the new aggchain metadata manager
*/
function setAggchainMetadataManager(
address newAggchainMetadataManager
) external onlyAggchainManager {
address oldAggchainMetadataManager = aggchainMetadataManager;
aggchainMetadataManager = newAggchainMetadataManager;
emit SetAggchainMetadataManager(
oldAggchainMetadataManager,
newAggchainMetadataManager
);
}
/**
* @notice Enable the use of default verification keys from gateway
*/
function enableUseDefaultVkeysFlag() external virtual onlyAggchainManager {
if (useDefaultVkeys) {
revert UseDefaultVkeysAlreadyEnabled();
}
useDefaultVkeys = true;
// Emit event
emit EnableUseDefaultVkeysFlag();
}
/**
* @notice Disable the use of default verification keys from gateway
*/
function disableUseDefaultVkeysFlag() external virtual onlyAggchainManager {
if (!useDefaultVkeys) {
revert UseDefaultVkeysAlreadyDisabled();
}
useDefaultVkeys = false;
// Emit event
emit DisableUseDefaultVkeysFlag();
}
/**
* @notice Enable the use of default signers from gateway
*/
function enableUseDefaultSignersFlag() external onlyAggchainManager {
if (useDefaultSigners) {
revert UseDefaultSignersAlreadyEnabled();
}
useDefaultSigners = true;
// Emit event
emit EnableUseDefaultSignersFlag();
}
/**
* @notice Disable the use of default signers from gateway
*/
function disableUseDefaultSignersFlag() external onlyAggchainManager {
if (!useDefaultSigners) {
revert UseDefaultSignersAlreadyDisabled();
}
useDefaultSigners = false;
// Emit event
emit DisableUseDefaultSignersFlag();
}
/**
* @notice Add a new aggchain verification key to the aggchain contract.
* @param aggchainVKeySelector The selector for the verification key query. This selector identifies the aggchain key
* @param newAggchainVKey The new aggchain verification key to be added.
*/
function addOwnedAggchainVKey(
bytes4 aggchainVKeySelector,
bytes32 newAggchainVKey
) external virtual onlyAggchainManager {
if (newAggchainVKey == bytes32(0)) {
revert ZeroValueAggchainVKey();
}
// Check if proposed selector has already a verification key assigned
if (ownedAggchainVKeys[aggchainVKeySelector] != bytes32(0)) {
revert OwnedAggchainVKeyAlreadyAdded();
}
ownedAggchainVKeys[aggchainVKeySelector] = newAggchainVKey;
emit AddAggchainVKey(aggchainVKeySelector, newAggchainVKey);
}
/**
* @notice Update the aggchain verification key in the aggchain contract.
* @param aggchainVKeySelector The selector for the verification key query. This selector identifies the aggchain key
* @param updatedAggchainVKey The updated aggchain verification key value.
*/
function updateOwnedAggchainVKey(
bytes4 aggchainVKeySelector,
bytes32 updatedAggchainVKey
) external virtual onlyAggchainManager {
// Check already added
if (ownedAggchainVKeys[aggchainVKeySelector] == bytes32(0)) {
revert OwnedAggchainVKeyNotFound();
}
bytes32 previousAggchainVKey = ownedAggchainVKeys[aggchainVKeySelector];
ownedAggchainVKeys[aggchainVKeySelector] = updatedAggchainVKey;
emit UpdateAggchainVKey(
aggchainVKeySelector,
previousAggchainVKey,
updatedAggchainVKey
);
}
/**
* @notice Sets or updates metadata for the aggchain.
* @dev Can only be called by the aggchain metadata manager. Empty values are allowed to clear metadata.
* @param key The metadata key to set.
* @param value The metadata value to set.
*/
function setAggchainMetadata(
string calldata key,
string calldata value
) external onlyAggchainMetadataManager {
_setAggchainMetadataInternal(key, value);
}
/**
* @notice Sets or updates multiple metadata entries in a single transaction.
* @dev Can only be called by the aggchain metadata manager.
* @param keys Array of metadata keys to set.
* @param values Array of metadata values to set (must be same length as keys).
*/
function batchSetAggchainMetadata(
string[] calldata keys,
string[] calldata values
) external onlyAggchainMetadataManager {
uint256 length = keys.length;
if (length != values.length) {
revert MetadataArrayLengthMismatch();
}
for (uint256 i = 0; i < length; i++) {
_setAggchainMetadataInternal(keys[i], values[i]);
}
}
//////////////////////////
// view functions //
//////////////////////////
/**
* @notice returns the current aggchain verification key. If the flag `useDefaultVkeys` is set to true, the gateway verification key is returned, else, the custom chain verification key is returned.
* @param aggchainVKeySelector The selector for the verification key query. This selector identifies the aggchain type + sp1 verifier version
* @return aggchainVKey The verification key for the specified selector
*/
function getAggchainVKey(
bytes4 aggchainVKeySelector
) public view virtual returns (bytes32 aggchainVKey) {
if (useDefaultVkeys == false) {
aggchainVKey = ownedAggchainVKeys[aggchainVKeySelector];
if (aggchainVKey == bytes32(0)) {
revert AggchainVKeyNotFound();
}
} else {
// Retrieve aggchain key from AgglayerGateway
aggchainVKey = aggLayerGateway.getDefaultAggchainVKey(
aggchainVKeySelector
);
}
}
/**
* @notice Computes the selector for the aggchain verification key from the aggchain type and the aggchainVKeyVersion.
* @dev It joins two bytes2 values into a bytes4 value.
* @param aggchainVKeyVersion The aggchain verification key version, used to identify the aggchain verification key.
* @param aggchainType The aggchain type, hardcoded in the aggchain contract.
* @return getAggchainVKeySelector computed bytes4 selector combining version and type
* [ aggchainVKeySelector ]
* [ aggchainVKeyVersion | AGGCHAIN_TYPE ]
* [ 2 bytes | 2 bytes ]
*/
function getAggchainVKeySelector(
bytes2 aggchainVKeyVersion,
bytes2 aggchainType
) public pure returns (bytes4) {
return bytes4(aggchainVKeyVersion) | (bytes4(aggchainType) >> 16);
}
/**
* @notice Computes the aggchainType from the aggchainVKeySelector.
* @param aggchainVKeySelector The aggchain verification key selector.
* @return AGGCHAIN_TYPE extracted aggchain type (last 2 bytes)
* [ aggchainVKeySelector ]
* [ aggchainVKeyVersion | AGGCHAIN_TYPE ]
* [ 2 bytes | 2 bytes ]
*/
function getAggchainTypeFromSelector(
bytes4 aggchainVKeySelector
) public pure returns (bytes2) {
return bytes2(aggchainVKeySelector << 16);
}
/**
* @notice Computes the aggchainVKeyVersion from the aggchainVKeySelector.
* @param aggchainVKeySelector The aggchain verification key selector.
* @return aggchainVKeyVersion extracted aggchain verification key version (first 2 bytes)
* [ aggchainVKeySelector ]
* [ aggchainVKeyVersion | AGGCHAIN_TYPE ]
* [ 2 bytes | 2 bytes ]
*/
function getAggchainVKeyVersionFromSelector(
bytes4 aggchainVKeySelector
) public pure returns (bytes2) {
return bytes2(aggchainVKeySelector);
}
/**
* @notice Get the threshold for the multisig
* @return threshold for the multisig
*/
function getThreshold() external view returns (uint256) {
if (useDefaultSigners) {
return aggLayerGateway.getThreshold();
}
return threshold;
}
/**
* @notice Check if an address is a signer
* @param _signer Address to check
* @return True if the address is a signer
*/
function isSigner(address _signer) public view returns (bool) {
if (useDefaultSigners) {
return aggLayerGateway.isSigner(_signer);
}
return bytes(signerToURLs[_signer]).length > 0;
}
/**
* @notice Get the number of aggchainSigners
* @return Number of aggchainSigners in the multisig
*/
function getAggchainSignersCount() external view returns (uint256) {
if (useDefaultSigners) {
return aggLayerGateway.getAggchainSignersCount();
}
return aggchainSigners.length;
}
/**
* @notice Get all aggchainSigners
* @return Array of signer addresses
*/
function getAggchainSigners() external view returns (address[] memory) {
if (useDefaultSigners) {
return aggLayerGateway.getAggchainSigners();
}
return aggchainSigners;
}
/**
* @notice Get the aggchain signers hash
* @return The aggchain signers hash
*/
function getAggchainMultisigHash() public view returns (bytes32) {
if (useDefaultSigners) {
return aggLayerGateway.getAggchainMultisigHash();
}
// Sanity check to realize earlier that the aggchainMultisigHash has not been set given
// that the proof cannot be computed since there is no hash reconstruction to be 0
if (aggchainMultisigHash == bytes32(0)) {
revert AggchainSignersHashNotInitialized();
}
return aggchainMultisigHash;
}
/**
* @notice Get all aggchainSigners with their URLs
* @return Array of SignerInfo structs containing signer addresses and URLs
*/
function getAggchainSignerInfos()
external
view
returns (SignerInfo[] memory)
{
if (useDefaultSigners) {
// Get signers with URLs directly from gateway
return aggLayerGateway.getAggchainSignerInfos();
} else {
// Use local aggchainSigners
SignerInfo[] memory signerInfos = new SignerInfo[](
aggchainSigners.length
);
for (uint256 i = 0; i < aggchainSigners.length; i++) {
signerInfos[i] = SignerInfo({
addr: aggchainSigners[i],
url: signerToURLs[aggchainSigners[i]]
});
}
return signerInfos;
}
}
////////////////////////////////////////////////////////////
// Internal Functions //
////////////////////////////////////////////////////////////
/**
* @notice Internal function to add a signer with validation
* @dev Validates that signer is not zero address, URL is not empty, and signer doesn't already exist
* @param _signer Address of the signer to add
* @param url URL associated with the signer
*/
function _addSignerInternal(address _signer, string memory url) internal {
if (_signer == address(0)) {
revert SignerCannotBeZero();
}
if (bytes(url).length == 0) {
revert SignerURLCannotBeEmpty();
}
if (bytes(signerToURLs[_signer]).length > 0) {
revert SignerAlreadyExists();
}
aggchainSigners.push(_signer);
signerToURLs[_signer] = url;
}
/**
* @notice Internal function to remove a signer with validation
* @dev Validates index bounds and that the signer at the index matches the provided address
* @param _signer Address of the signer to remove
* @param _signerIndex Index of the signer in the aggchainSigners array
*/
function _removeSignerInternal(
address _signer,
uint256 _signerIndex
) internal {
// Cache array length
uint256 signersLength = aggchainSigners.length;
// Validate input parameters
if (_signerIndex >= signersLength) {
revert SignerDoesNotExist();
}
if (aggchainSigners[_signerIndex] != _signer) {
revert SignerDoesNotExist();
}
// Remove from mapping
delete signerToURLs[_signer];
// Move the last element to the deleted spot and remove the last element
aggchainSigners[_signerIndex] = aggchainSigners[signersLength - 1];
aggchainSigners.pop();
}
/**
* @notice Update the hash of the aggchainSigners array
* @dev Combines threshold and signers array into a single hash for efficient verification
*/
function _updateAggchainMultisigHash() internal {
aggchainMultisigHash = keccak256(
abi.encodePacked(threshold, aggchainSigners)
);
emit SignersAndThresholdUpdated(
aggchainSigners,
threshold,
aggchainMultisigHash
);
}
/**
* @notice Internal function to set or update metadata for the aggchain
* @dev Empty values are allowed to clear metadata
* @param key The metadata key to set
* @param value The metadata value to set
*/
function _setAggchainMetadataInternal(
string memory key,
string memory value
) internal {
aggchainMetadata[key] = value;
emit AggchainMetadataSet(key, value);
}
/**
* @dev Internal function to validate VKeys consistency
* @param _useDefaultVkeys Whether to use default verification keys
* @param _initAggchainVKeySelector The aggchain verification key selector
* @param _initOwnedAggchainVKey The owned aggchain verification key
* @param aggchainType The expected aggchain type
*/
function _validateVKeysConsistency(
bool _useDefaultVkeys,
bytes4 _initAggchainVKeySelector,
bytes32 _initOwnedAggchainVKey,
bytes2 aggchainType
) internal pure {
// Check the use default vkeys is consistent
if (_useDefaultVkeys) {
if (
_initAggchainVKeySelector != bytes4(0) ||
_initOwnedAggchainVKey != bytes32(0)
) {
revert InvalidInitAggchainVKey();
}
} else {
if (
getAggchainTypeFromSelector(_initAggchainVKeySelector) !=
aggchainType
) {
revert InvalidAggchainType();
}
}
}
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
import {IEmergencyManager} from "../interfaces/IEmergencyManager.sol";
/**
* @dev Contract helper responsible to manage the emergency state
*/
contract EmergencyManager is IEmergencyManager {
/**
* @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.
*/
/// @custom:oz-renamed-from _gap
uint256[10] private __gap;
// Indicates whether the emergency state is active or not
bool public isEmergencyState;
/**
* @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();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/Hashes.sol)
pragma solidity ^0.8.20;
/**
* @dev Library of standard hash functions.
* @notice This code is a copy from OpenZeppelin Contracts v5.1.0 (utils/cryptography/Hashes.sol) with a minor change:
* function visibility is modified from 'private' to 'internal' so it can be used in other contracts.
* @notice OpenZeppelin already did this change: https://github.com/OpenZeppelin/openzeppelin-contracts/commit/441dc141ac99622de7e535fa75dfc74af939019c
* to be included in next version of OpenZeppelin Contracts.
* _Available since v5.1._
*/
library Hashes {
/**
* @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory.
*/
function efficientKeccak256(
bytes32 a,
bytes32 b
) internal pure returns (bytes32 value) {
assembly ("memory-safe") {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
/**
* Since the current contract of PolygonZkEVM will be upgraded to a AgglayerManager 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;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import "@openzeppelin/contracts-upgradeable4/access/IAccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable4/utils/ContextUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable4/utils/StringsUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable4/utils/introspection/ERC165Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable4/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;
}// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.20;
import "@openzeppelin/contracts-upgradeable4/token/ERC20/utils/SafeERC20Upgradeable.sol";
import "../interfaces/IAgglayerGER.sol";
import "@openzeppelin/contracts-upgradeable4/proxy/utils/Initializable.sol";
import "../interfaces/IPolygonZkEVMErrors.sol";
import "../interfaces/IPolygonZkEVMEtrogErrors.sol";
import "../interfaces/IPolygonConsensusBase.sol";
import "../interfaces/IPolygonRollupBase.sol";
import "../interfaces/IAgglayerBridge.sol";
import "@openzeppelin/contracts-upgradeable4/token/ERC20/extensions/IERC20MetadataUpgradeable.sol";
import "./PolygonConstantsBase.sol";
import "../AgglayerManager.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 PolygonConsensusBase is
Initializable,
IPolygonConsensusBase,
IPolygonZkEVMEtrogErrors
{
// POL token address
IERC20Upgradeable public immutable pol;
// Global Exit Root interface
IAgglayerGER public immutable globalExitRootManager;
// PolygonZkEVM Bridge Address
IAgglayerBridge public immutable bridgeAddress;
// Rollup manager
AgglayerManager 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.
*/
/// @custom:oz-renamed-from _gap
uint256[50] private __gap;
/**
* @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 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(
IAgglayerGER _globalExitRootManager,
IERC20Upgradeable _pol,
IAgglayerBridge _bridgeAddress,
AgglayerManager _rollupManager
) {
globalExitRootManager = _globalExitRootManager;
pol = _pol;
bridgeAddress = _bridgeAddress;
rollupManager = _rollupManager;
// Disable initializers on the implementation following the best practices
_disableInitializers();
}
/**
* @param _admin Admin address
* @param sequencer Trusted sequencer address
* @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 {
_initializePolygonConsensusBase(
_admin,
sequencer,
_gasTokenAddress,
sequencerURL,
_networkName
);
}
/**
* @param _admin Admin address
* @param sequencer Trusted sequencer address
* @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 _initializePolygonConsensusBase(
address _admin,
address sequencer,
address _gasTokenAddress,
string memory sequencerURL,
string memory _networkName
) internal {
if (_admin == address(0)) {
revert AdminCannotBeZeroAddress();
}
admin = _admin;
trustedSequencer = sequencer;
trustedSequencerURL = sequencerURL;
networkName = _networkName;
gasTokenAddress = _gasTokenAddress;
}
modifier onlyAdmin() {
if (admin != msg.sender) {
revert OnlyAdmin();
}
_;
}
modifier onlyRollupManager() {
if (address(rollupManager) != msg.sender) {
revert OnlyRollupManager();
}
_;
}
//////////////////
// 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 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);
}
}// 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;
}// 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 Contract TransparentUpgradeableProxy from Openzeppelin v5 with the following modifications:
* - Admin is a parameter in the constructor ( like previous versions) instead 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);
}
}{
"optimizer": {
"enabled": true,
"runs": 999999
},
"evmVersion": "cancun",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IAgglayerGER","name":"_globalExitRootManager","type":"address"},{"internalType":"contract IERC20Upgradeable","name":"_pol","type":"address"},{"internalType":"contract IAgglayerBridge","name":"_bridgeAddress","type":"address"},{"internalType":"contract AgglayerManager","name":"_rollupManager","type":"address"},{"internalType":"contract IAgglayerGateway","name":"_aggLayerGateway","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AdminCannotBeZeroAddress","type":"error"},{"inputs":[],"name":"AggchainManagerAlreadyInitialized","type":"error"},{"inputs":[],"name":"AggchainManagerCannotBeZero","type":"error"},{"inputs":[],"name":"AggchainSignersHashNotInitialized","type":"error"},{"inputs":[],"name":"AggchainSignersTooHigh","type":"error"},{"inputs":[],"name":"AggchainVKeyNotFound","type":"error"},{"inputs":[],"name":"BatchAlreadyVerified","type":"error"},{"inputs":[],"name":"BatchNotSequencedOrNotSequenceEnd","type":"error"},{"inputs":[],"name":"ConflictingDefaultSignersConfiguration","type":"error"},{"inputs":[],"name":"ExceedMaxVerifyBatches","type":"error"},{"inputs":[],"name":"FinalAccInputHashDoesNotMatch","type":"error"},{"inputs":[],"name":"FinalNumBatchBelowLastVerifiedBatch","type":"error"},{"inputs":[],"name":"FinalNumBatchDoesNotMatchPendingState","type":"error"},{"inputs":[],"name":"FinalPendingStateNumInvalid","type":"error"},{"inputs":[],"name":"ForceBatchNotAllowed","type":"error"},{"inputs":[],"name":"ForceBatchTimeoutNotExpired","type":"error"},{"inputs":[],"name":"ForceBatchesAlreadyActive","type":"error"},{"inputs":[],"name":"ForceBatchesDecentralized","type":"error"},{"inputs":[],"name":"ForceBatchesNotAllowedOnEmergencyState","type":"error"},{"inputs":[],"name":"ForceBatchesOverflow","type":"error"},{"inputs":[],"name":"ForcedDataDoesNotMatch","type":"error"},{"inputs":[],"name":"FunctionNotSupported","type":"error"},{"inputs":[],"name":"GasTokenNetworkMustBeZeroOnEther","type":"error"},{"inputs":[],"name":"GlobalExitRootNotExist","type":"error"},{"inputs":[],"name":"HaltTimeoutNotExpired","type":"error"},{"inputs":[],"name":"HaltTimeoutNotExpiredAfterEmergencyState","type":"error"},{"inputs":[],"name":"HugeTokenMetadataNotSupported","type":"error"},{"inputs":[],"name":"IndicesNotInDescendingOrder","type":"error"},{"inputs":[],"name":"InitNumBatchAboveLastVerifiedBatch","type":"error"},{"inputs":[],"name":"InitNumBatchDoesNotMatchPendingState","type":"error"},{"inputs":[],"name":"InitSequencedBatchDoesNotMatch","type":"error"},{"inputs":[],"name":"InvalidAggchainDataLength","type":"error"},{"inputs":[],"name":"InvalidAggchainType","type":"error"},{"inputs":[],"name":"InvalidInitAggchainVKey","type":"error"},{"inputs":[],"name":"InvalidInitializeFunction","type":"error"},{"inputs":[],"name":"InvalidInitializeTransaction","type":"error"},{"inputs":[],"name":"InvalidInitializer","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[],"name":"InvalidRangeBatchTimeTarget","type":"error"},{"inputs":[],"name":"InvalidRangeForceBatchTimeout","type":"error"},{"inputs":[],"name":"InvalidRangeMultiplierBatchFee","type":"error"},{"inputs":[],"name":"InvalidThreshold","type":"error"},{"inputs":[],"name":"InvalidZeroAddress","type":"error"},{"inputs":[],"name":"L1InfoTreeLeafCountInvalid","type":"error"},{"inputs":[],"name":"MaxTimestampSequenceInvalid","type":"error"},{"inputs":[],"name":"MetadataArrayLengthMismatch","type":"error"},{"inputs":[],"name":"NewAccInputHashDoesNotExist","type":"error"},{"inputs":[],"name":"NewPendingStateTimeoutMustBeLower","type":"error"},{"inputs":[],"name":"NewStateRootNotInsidePrime","type":"error"},{"inputs":[],"name":"NewTrustedAggregatorTimeoutMustBeLower","type":"error"},{"inputs":[],"name":"NotEnoughMaticAmount","type":"error"},{"inputs":[],"name":"NotEnoughPOLAmount","type":"error"},{"inputs":[],"name":"OldAccInputHashDoesNotExist","type":"error"},{"inputs":[],"name":"OldStateRootDoesNotExist","type":"error"},{"inputs":[],"name":"OnlyAdmin","type":"error"},{"inputs":[],"name":"OnlyAggchainManager","type":"error"},{"inputs":[],"name":"OnlyAggchainMetadataManager","type":"error"},{"inputs":[],"name":"OnlyPendingAdmin","type":"error"},{"inputs":[],"name":"OnlyPendingAggchainManager","type":"error"},{"inputs":[],"name":"OnlyRollupManager","type":"error"},{"inputs":[],"name":"OnlyTrustedAggregator","type":"error"},{"inputs":[],"name":"OnlyTrustedSequencer","type":"error"},{"inputs":[],"name":"OwnedAggchainVKeyAlreadyAdded","type":"error"},{"inputs":[],"name":"OwnedAggchainVKeyNotFound","type":"error"},{"inputs":[],"name":"PendingStateDoesNotExist","type":"error"},{"inputs":[],"name":"PendingStateInvalid","type":"error"},{"inputs":[],"name":"PendingStateNotConsolidable","type":"error"},{"inputs":[],"name":"PendingStateTimeoutExceedHaltAggregationTimeout","type":"error"},{"inputs":[],"name":"SequenceZeroBatches","type":"error"},{"inputs":[],"name":"SequencedTimestampBelowForcedTimestamp","type":"error"},{"inputs":[],"name":"SequencedTimestampInvalid","type":"error"},{"inputs":[],"name":"SignerAlreadyExists","type":"error"},{"inputs":[],"name":"SignerCannotBeZero","type":"error"},{"inputs":[],"name":"SignerDoesNotExist","type":"error"},{"inputs":[],"name":"SignerURLCannotBeEmpty","type":"error"},{"inputs":[],"name":"StoredRootMustBeDifferentThanNewRoot","type":"error"},{"inputs":[],"name":"TransactionsLengthAboveMax","type":"error"},{"inputs":[],"name":"TrustedAggregatorTimeoutExceedHaltAggregationTimeout","type":"error"},{"inputs":[],"name":"TrustedAggregatorTimeoutNotExpired","type":"error"},{"inputs":[],"name":"UseDefaultSignersAlreadyDisabled","type":"error"},{"inputs":[],"name":"UseDefaultSignersAlreadyEnabled","type":"error"},{"inputs":[],"name":"UseDefaultVkeysAlreadyDisabled","type":"error"},{"inputs":[],"name":"UseDefaultVkeysAlreadyEnabled","type":"error"},{"inputs":[],"name":"ZeroValueAggchainVKey","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AcceptAdminRole","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAggchainManager","type":"address"},{"indexed":false,"internalType":"address","name":"newAggchainManager","type":"address"}],"name":"AcceptAggchainManagerRole","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"bytes32","name":"newAggchainVKey","type":"bytes32"}],"name":"AddAggchainVKey","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"string","name":"value","type":"string"}],"name":"AggchainMetadataSet","type":"event"},{"anonymous":false,"inputs":[],"name":"DisableUseDefaultSignersFlag","type":"event"},{"anonymous":false,"inputs":[],"name":"DisableUseDefaultVkeysFlag","type":"event"},{"anonymous":false,"inputs":[],"name":"EnableUseDefaultSignersFlag","type":"event"},{"anonymous":false,"inputs":[],"name":"EnableUseDefaultVkeysFlag","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[],"name":"OnVerifyPessimisticECDSAMultisig","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAggchainMetadataManager","type":"address"},{"indexed":false,"internalType":"address","name":"newAggchainMetadataManager","type":"address"}],"name":"SetAggchainMetadataManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newTrustedSequencer","type":"address"}],"name":"SetTrustedSequencer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"newTrustedSequencerURL","type":"string"}],"name":"SetTrustedSequencerURL","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"aggchainSigners","type":"address[]"},{"indexed":false,"internalType":"uint256","name":"newThreshold","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"newAggchainMultisigHash","type":"bytes32"}],"name":"SignersAndThresholdUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"TransferAdminRole","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"currentAggchainManager","type":"address"},{"indexed":false,"internalType":"address","name":"newPendingAggchainManager","type":"address"}],"name":"TransferAggchainManagerRole","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"bytes32","name":"previousAggchainVKey","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"newAggchainVKey","type":"bytes32"}],"name":"UpdateAggchainVKey","type":"event"},{"inputs":[],"name":"AGGCHAIN_ECDSA_MULTISIG_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"AGGCHAIN_TYPE","outputs":[{"internalType":"bytes2","name":"","type":"bytes2"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CONSENSUS_TYPE","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_AGGCHAIN_SIGNERS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_legacypendingVKeyManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_legacyvKeyManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptAdminRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"acceptAggchainManagerRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"","type":"bytes4"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"addOwnedAggchainVKey","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aggLayerGateway","outputs":[{"internalType":"contract IAgglayerGateway","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aggchainManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"aggchainMetadata","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aggchainMetadataManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"aggchainMultisigHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"aggchainSigners","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string[]","name":"keys","type":"string[]"},{"internalType":"string[]","name":"values","type":"string[]"}],"name":"batchSetAggchainMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bridgeAddress","outputs":[{"internalType":"contract IAgglayerBridge","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disableUseDefaultSignersFlag","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"disableUseDefaultVkeysFlag","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"enableUseDefaultSignersFlag","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enableUseDefaultVkeysFlag","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"forceBatchAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"forceBatchTimeout","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"forcedBatches","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasTokenNetwork","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"aggchainData","type":"bytes"}],"name":"getAggchainHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAggchainMultisigHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAggchainSignerInfos","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"string","name":"url","type":"string"}],"internalType":"struct IAggchainSigners.SignerInfo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAggchainSigners","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAggchainSignersCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"aggchainVKeySelector","type":"bytes4"}],"name":"getAggchainTypeFromSelector","outputs":[{"internalType":"bytes2","name":"","type":"bytes2"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"name":"getAggchainVKey","outputs":[{"internalType":"bytes32","name":"aggchainVKey","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes2","name":"aggchainVKeyVersion","type":"bytes2"},{"internalType":"bytes2","name":"aggchainType","type":"bytes2"}],"name":"getAggchainVKeySelector","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes4","name":"aggchainVKeySelector","type":"bytes4"}],"name":"getAggchainVKeyVersionFromSelector","outputs":[{"internalType":"bytes2","name":"","type":"bytes2"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"aggchainData","type":"bytes"}],"name":"getVKeyAndAggchainParams","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"globalExitRootManager","outputs":[{"internalType":"contract IAgglayerGER","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newAggchainManager","type":"address"}],"name":"initAggchainManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_admin","type":"address"},{"internalType":"address","name":"_trustedSequencer","type":"address"},{"internalType":"address","name":"_gasTokenAddress","type":"address"},{"internalType":"string","name":"_trustedSequencerURL","type":"string"},{"internalType":"string","name":"_networkName","type":"string"},{"internalType":"bool","name":"_useDefaultSigners","type":"bool"},{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"string","name":"url","type":"string"}],"internalType":"struct IAggchainSigners.SignerInfo[]","name":"_signersToAdd","type":"tuple[]"},{"internalType":"uint256","name":"_newThreshold","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"address","name":"","type":"address"},{"internalType":"string","name":"","type":"string"},{"internalType":"string","name":"","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"isSigner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastAccInputHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastForceBatch","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastForceBatchSequenced","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"migrateFromLegacyConsensus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"networkName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"aggchainData","type":"bytes"}],"name":"onVerifyPessimistic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"aggchainVKeySelector","type":"bytes4"}],"name":"ownedAggchainVKeys","outputs":[{"internalType":"bytes32","name":"ownedAggchainVKey","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingAggchainManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pol","outputs":[{"internalType":"contract IERC20Upgradeable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rollupManager","outputs":[{"internalType":"contract AgglayerManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"key","type":"string"},{"internalType":"string","name":"value","type":"string"}],"name":"setAggchainMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAggchainMetadataManager","type":"address"}],"name":"setAggchainMetadataManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTrustedSequencer","type":"address"}],"name":"setTrustedSequencer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newTrustedSequencerURL","type":"string"}],"name":"setTrustedSequencerURL","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"signerToURLs","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"threshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newPendingAdmin","type":"address"}],"name":"transferAdminRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAggchainManager","type":"address"}],"name":"transferAggchainManagerRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"trustedSequencer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trustedSequencerURL","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"","type":"bytes4"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"updateOwnedAggchainVKey","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"internalType":"struct IAggchainSigners.RemoveSignerInfo[]","name":"_signersToRemove","type":"tuple[]"},{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"string","name":"url","type":"string"}],"internalType":"struct IAggchainSigners.SignerInfo[]","name":"_signersToAdd","type":"tuple[]"},{"internalType":"uint256","name":"_newThreshold","type":"uint256"}],"name":"updateSignersAndThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"useDefaultSigners","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"useDefaultVkeys","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"}]Contract Creation Code
610120604052348015610010575f5ffd5b506040516144e73803806144e783398101604081905261002f916101c4565b6001600160a01b0380861660a05280851660805280841660c052821660e05284848484848484848461005f6100f0565b505050506001600160a01b038116158061008057506001600160a01b038516155b8061009257506001600160a01b038416155b806100a457506001600160a01b038316155b806100b657506001600160a01b038216155b156100d45760405163f6b2911f60e01b815260040160405180910390fd5b6001600160a01b03166101005250610235975050505050505050565b5f54610100900460ff161561015b5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b5f5460ff90811610156101ab575f805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6001600160a01b03811681146101c1575f5ffd5b50565b5f5f5f5f5f60a086880312156101d8575f5ffd5b85516101e3816101ad565b60208701519095506101f4816101ad565b6040870151909450610205816101ad565b6060870151909350610216816101ad565b6080870151909250610227816101ad565b809150509295509295909350565b60805160a05160c05160e051610100516142366102b15f395f8181610958015281816113740152818161166701528181611c3a0152818161248d01528181612547015261265c01525f818161072d01528181610c1f01528181611db1015261202401525f61091e01525f610a3301525f610a8201526142365ff3fe608060405234801561000f575f5ffd5b5060043610610441575f3560e01c80636e7fbce911610243578063c754c7ed11610148578063e75235b8116100c3578063effb847911610093578063f851a44011610079578063f851a44014610b03578063fc5014d614610b28578063fd7d249314610b4d575f5ffd5b8063effb847914610ad1578063f51f563a14610af0575f5ffd5b8063e75235b814610aa4578063e7a7ed0214610aac578063e90a340914610ac0578063efe6c9f41461049d575f5ffd5b8063cea5a4c011610118578063d02103ca116100fe578063d02103ca14610a2e578063d9c2853914610a55578063e46761c414610a7d575f5ffd5b8063cea5a4c014610a06578063cfa8ed4714610a0e575f5ffd5b8063c754c7ed146109bb578063c89e42df146109e3578063ca69e7dc146109f6578063cce7d0df146109fe575f5ffd5b80638c3d7301116101d8578063ab0475cf116101a8578063b3a326f71161018e578063b3a326f71461098d578063bdfbed7e146109a0578063be647d03146109b3575f5ffd5b8063ab0475cf14610953578063ada8f9191461097a575f5ffd5b80638c3d7301146108fe5780639ee4afa314610906578063a3c573eb14610919578063a8d31bd914610940575f5ffd5b806374f0b0c11161021357806374f0b0c114610887578063750a6e72146108a7578063759664d4146108af5780637df73e27146108eb575f5ffd5b80636e7fbce91461083a5780636ff512cc1461084157806371257022146108545780637388c43614610867575f5ffd5b806339b7ec1611610349578063527570f1116102de5780635ecaca2b116102ae5780636a55f66c116102945780636a55f66c146107ff5780636b8616ce146108125780636e05d2cd14610831575f5ffd5b80635ecaca2b146107cc578063697427f6146107ec575f5ffd5b8063527570f114610758578063542028d51461077857806354fd4d501461078057806359a03e0f146107b9575f5ffd5b806342cde4e81161031957806342cde4e8146106e657806345605267146106ef57806349b7b802146107285780634a5db0c11461074f575f5ffd5b806339b7ec16146106545780633c351e10146106745780633cbc795b146106945780633e1e0121146106d1575f5ffd5b806319451a8f116103d95780632c111c06116103a9578063349d40461161038f578063349d40461461061957806335acd6c21461062e57806336cd6b5b14610641575f5ffd5b80632c111c06146105f9578063314eb17b146104f6575f5ffd5b806319451a8f146104f65780631d0b435e14610509578063267822471461054d57806326f9b76d14610592575f5ffd5b80631489e707116104145780631489e7071461049d578063153c3b7f146104a557806315981b29146104b8578063188d9180146104c0575f5ffd5b806301fcf6a014610445578063052358be1461046b57806306e7666514610480578063107bf28c14610488575b5f5ffd5b6104586104533660046132ae565b505f90565b6040519081526020015b60405180910390f35b61047e610479366004613313565b610b55565b005b61047e610c1d565b610490610fb6565b60405161046291906133cb565b61047e611042565b61047e6104b336600461341e565b6110c5565b61047e611224565b603e546104e6907501000000000000000000000000000000000000000000900460ff1681565b6040519015158152602001610462565b61047e61050436600461347e565b611042565b61051c6105173660046134d5565b6112fb565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610462565b60015461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610462565b6105c86105a03660046132ae565b60101b7fffff0000000000000000000000000000000000000000000000000000000000001690565b6040517fffff0000000000000000000000000000000000000000000000000000000000009091168152602001610462565b60085461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b61062161134b565b6040516104629190613506565b61056d61063c3660046135b4565b6115f1565b61049061064f3660046135f7565b611626565b60465461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b60095461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b6009546106bc9074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610462565b6106d961163e565b6040516104629190613612565b61045860445481565b60075461070f9068010000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610462565b61056d7f000000000000000000000000000000000000000000000000000000000000000081565b61045860455481565b60405461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b61049061177d565b60408051808201909152600681527f76312e302e3000000000000000000000000000000000000000000000000000006020820152610490565b6104906107c73660046137ad565b61178a565b603d5461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b61047e6107fa36600461391c565b6117ae565b61045861080d3660046139f7565b611a5a565b610458610820366004613a3c565b60066020525f908152604090205481565b61045860055481565b6105c85f81565b61047e61084f3660046135f7565b611ad4565b61047e610862366004613a63565b611b9d565b603f5461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b603e5461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b61045860ff81565b6104906040518060400160405280600681526020017f76312e302e30000000000000000000000000000000000000000000000000000081525081565b6104e66108f93660046135f7565b611bcf565b61047e611cdc565b61047e610914366004613b17565b611daf565b61056d7f000000000000000000000000000000000000000000000000000000000000000081565b61047e61094e3660046135f7565b611e82565b61056d7f000000000000000000000000000000000000000000000000000000000000000081565b61047e6109883660046135f7565b611f59565b61047e61099b3660046135f7565b612022565b61047e6109ae3660046135f7565b6121a8565b61047e6122c2565b60075461070f90700100000000000000000000000000000000900467ffffffffffffffff1681565b61047e6109f13660046137ad565b6123d3565b610458612465565b61045861251f565b6106bc600181565b60025461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b61056d7f000000000000000000000000000000000000000000000000000000000000000081565b610a68610a633660046139f7565b6125ee565b60408051928352602083019190915201610462565b61056d7f000000000000000000000000000000000000000000000000000000000000000081565b610458612634565b60075461070f9067ffffffffffffffff1681565b6105c8610ace3660046132ae565b90565b610458610adf3660046132ae565b60416020525f908152604090205481565b61047e610afe366004613b56565b6126ca565b5f5461056d9062010000900473ffffffffffffffffffffffffffffffffffffffff1681565b603e546104e69074010000000000000000000000000000000000000000900460ff1681565b61047e61272b565b60465473ffffffffffffffffffffffffffffffffffffffff163314610ba6576040517fd0c34d9700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c1784848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050604080516020601f880181900481028201810190925286815292508691508590819084018382808284375f9201919091525061282392505050565b50505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314610c8c576040517fb9b3a2c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805460ff16907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815c168217905d505f54600290610100900460ff16158015610cdc57505f5460ff8083169116105b610d6d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff80841691909117610100178255905c16600114610ddd576040517fadc06ae700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f54603f80546201000090920473ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff000000000000000000000000000000000000000090921691909117905560038054610e3790613c49565b90505f03610e9b5760025460408051808201909152600681527f4e4f5f55524c00000000000000000000000000000000000000000000000000006020820152610e969173ffffffffffffffffffffffffffffffffffffffff16906128a0565b610f48565b60025460038054610f489273ffffffffffffffffffffffffffffffffffffffff169190610ec790613c49565b80601f0160208091040260200160405190810160405280929190818152602001828054610ef390613c49565b8015610f3e5780601f10610f1557610100808354040283529160200191610f3e565b820191905f5260205f20905b815481529060010190602001808311610f2157829003601f168201915b50505050506128a0565b6001604455610f55612a15565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a150565b60048054610fc390613c49565b80601f0160208091040260200160405190810160405280929190818152602001828054610fef90613c49565b801561103a5780601f106110115761010080835404028352916020019161103a565b820191905f5260205f20905b81548152906001019060200180831161101d57829003601f168201915b505050505081565b603f5473ffffffffffffffffffffffffffffffffffffffff163314611093576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fd37a223a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60465473ffffffffffffffffffffffffffffffffffffffff163314611116576040517fd0c34d9700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82818114611150576040517f059d0ac900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b8181101561121c5761121486868381811061116f5761116f613c94565b90506020028101906111819190613cc1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152508892508791508590508181106111c9576111c9613c94565b90506020028101906111db9190613cc1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061282392505050565b600101611152565b505050505050565b60405473ffffffffffffffffffffffffffffffffffffffff163314611275576040517f3ac87ac900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603f80546040805473ffffffffffffffffffffffffffffffffffffffff8082167fffffffffffffffffffffffff000000000000000000000000000000000000000080861682179096559490911682558151921680835260208301939093527f67c02ffba2f5329171ad235a360497af6ac3cfe82f1412866fbbf2dd3556ed3f9101610fab565b7fffff00000000000000000000000000000000000000000000000000000000000082167dffff00000000000000000000000000000000000000000000000000000000601083901c16175b92915050565b603e546060907501000000000000000000000000000000000000000000900460ff1615611424577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663349d40466040518163ffffffff1660e01b81526004015f60405180830381865afa1580156113da573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261141f9190810190613d22565b905090565b6042545f9067ffffffffffffffff8111156114415761144161366a565b60405190808252806020026020018201604052801561148657816020015b604080518082019091525f81526060602082015281526020019060019003908161145f5790505b5090505f5b6042548110156115eb576040518060400160405280604283815481106114b3576114b3613c94565b905f5260205f20015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200160435f6042858154811061150c5761150c613c94565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff1683528201929092526040019020805461154790613c49565b80601f016020809104026020016040519081016040528092919081815260200182805461157390613c49565b80156115be5780601f10611595576101008083540402835291602001916115be565b820191905f5260205f20905b8154815290600101906020018083116115a157829003601f168201915b50505050508152508282815181106115d8576115d8613c94565b602090810291909101015260010161148b565b50919050565b60428181548110611600575f80fd5b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b60436020525f908152604090208054610fc390613c49565b603e546060907501000000000000000000000000000000000000000000900460ff1615611712577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16633e1e01216040518163ffffffff1660e01b81526004015f60405180830381865afa1580156116cd573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261141f9190810190613e82565b604280548060200260200160405190810160405280929190818152602001828054801561177357602002820191905f5260205f20905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611748575b5050505050905090565b60038054610fc390613c49565b805160208183018101805160478252928201919093012091528054610fc390613c49565b603f5473ffffffffffffffffffffffffffffffffffffffff1633146117ff576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805460ff16907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815c168217905d505f54600290610100900460ff1615801561184f57505f5460ff8083169116105b6118db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610d64565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff80841691909117610100178255905c1615611949576040517fadc06ae700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61195a89898989895f8a8180612a99565b83156119ac578251151580611970575060445415155b156119a7576040517f996c343000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119f2565b604080515f808252602082019092526119f2916119ea565b604080518082019091525f80825260208201528152602001906001900390816119c45790505b508484612bc1565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050505050565b5f5f611a6461251f565b90505f5f611a71856125ee565b6040517c010000000000000000000000000000000000000000000000000000000060208201526024810183905260448101829052606481018690529193509150608401604051602081830303815290604052805190602001209350505050919050565b5f5462010000900473ffffffffffffffffffffffffffffffffffffffff163314611b2a576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527ff54144f9611984021529f814a1cb6a41e22c58351510a0d9f7e822618abb9cc090602001610fab565b6040517ff57ac68300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603e545f907501000000000000000000000000000000000000000000900460ff1615611ca3576040517f7df73e2700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301527f00000000000000000000000000000000000000000000000000000000000000001690637df73e2790602401602060405180830381865afa158015611c7f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113459190613f1c565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526043602052604081208054611cd290613c49565b9050119050919050565b60015473ffffffffffffffffffffffffffffffffffffffff163314611d2d576040517fd1ec4b2300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001545f80547fffffffffffffffffffff0000000000000000000000000000000000000000ffff1673ffffffffffffffffffffffffffffffffffffffff9092166201000081029290921790556040519081527f056dc487bbf0795d0bbb1b4f0af523a855503cff740bfb4d5475f7a90c091e8e906020015b60405180910390a1565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314611e1e576040517fb9b3a2c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8015611e56576040517f3063965400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fc118263690a4306c74bd1bc80b55962addc2d9e61619ac0b2c2883badbbd01d8905f90a15050565b603f5473ffffffffffffffffffffffffffffffffffffffff163314611ed3576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6046805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f82ae2ec69f24a6de4517a5a45d4983651b578b3d8dc9262af5e352572fc64373910160405180910390a15050565b5f5462010000900473ffffffffffffffffffffffffffffffffffffffff163314611faf576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fa5b56b7906fd0a20e3f35120dd8343db1e12e037a6c90111c7e42885e82a1ce690602001610fab565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314612091576040517fb9b3a2c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603f5473ffffffffffffffffffffffffffffffffffffffff16156120e1576040517f257bb0bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811661212e576040517fd6bdac3f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603f80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316908117909155604080515f815260208101929092527f67c02ffba2f5329171ad235a360497af6ac3cfe82f1412866fbbf2dd3556ed3f9101610fab565b603f5473ffffffffffffffffffffffffffffffffffffffff1633146121f9576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116612246576040517ff6b2911f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182178355603f5483519116815260208101919091527fa3d8e5d045432398be30f83ce7c35a7bfc220c1b66cc5bf3f4dd4d539d93fab69101610fab565b603f5473ffffffffffffffffffffffffffffffffffffffff163314612313576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603e547501000000000000000000000000000000000000000000900460ff1615612369576040517f278d998800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603e80547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1675010000000000000000000000000000000000000000001790556040517f67ec953bdc8546ede08f8ee91e5205a1d1814e126cb8f5d00a918ddb1eaa292b905f90a1565b5f5462010000900473ffffffffffffffffffffffffffffffffffffffff163314612429576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60036124358282613f82565b507f6b8f723a4c7a5335cafae8a598a0aa0301be1387c037dccc085b62add6448b2081604051610fab91906133cb565b603e545f907501000000000000000000000000000000000000000000900460ff1615612518577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663ca69e7dc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124f4573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061141f9190614099565b5060425490565b603e545f907501000000000000000000000000000000000000000000900460ff16156125ae577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663cce7d0df6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124f4573d5f5f3e3d5ffd5b6045546125e7576040517fdd41f1ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060455490565b5f5f82515f1461262a576040517f3063965400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505f928392509050565b603e545f907501000000000000000000000000000000000000000000900460ff16156126c3577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e75235b86040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124f4573d5f5f3e3d5ffd5b5060445490565b603f5473ffffffffffffffffffffffffffffffffffffffff16331461271b576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612726838383612bc1565b505050565b603f5473ffffffffffffffffffffffffffffffffffffffff16331461277c576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603e547501000000000000000000000000000000000000000000900460ff166127d1576040517f5aa930a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603e80547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1690556040517f4c75580a56c734245a7418eb07d8a311e1bff79f982fed747da3589630e414be905f90a1565b8060478360405161283491906140b0565b9081526020016040518091039020908161284e9190613f82565b508160405161285d91906140b0565b60405180910390207f2779f9edd5ec4e0a99bffdea4008c8b979200959062a2bf00142acb939ca1b648260405161289491906133cb565b60405180910390a25050565b73ffffffffffffffffffffffffffffffffffffffff82166128ed576040517f7b3a0df600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80515f03612927576040517f8715f5fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82165f908152604360205260408120805461295690613c49565b90501115612990576040517f38615ecc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60428054600181019091557f38dfe4635b27babeca8be38d3b448cb5161a639b899a14825ba9c8d7892eb8c30180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091555f9081526043602052604090206127268282613f82565b6044546042604051602001612a2b9291906140c6565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052805160209091012060458190556044547f66d7b0647fdd512b69cbf4f8e1ce8068bfe0b236168e2704ba13b07425eaa74392611da59260429291614119565b5f54610100900460ff16612b2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610d64565b73ffffffffffffffffffffffffffffffffffffffff89161580612b66575073ffffffffffffffffffffffffffffffffffffffff8816155b15612b9d576040517ff6b2911f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612baa8989898989612db2565b612bb684848484612ee0565b505050505050505050565b600183511115612c69575f5b60018451612bdb91906141ad565b811015612c675783612bee8260016141c0565b81518110612bfe57612bfe613c94565b602002602001015160200151848281518110612c1c57612c1c613c94565b60200260200101516020015111612c5f576040517fb9a11d3100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600101612bcd565b505b5f5b8351811015612cbf57612cb7848281518110612c8957612c89613c94565b60200260200101515f0151858381518110612ca657612ca6613c94565b602002602001015160200151613036565b600101612c6b565b505f5b8251811015612d1657612d0e838281518110612ce057612ce0613c94565b60200260200101515f0151848381518110612cfd57612cfd613c94565b6020026020010151602001516128a0565b600101612cc2565b5060425460ff1015612d54576040517f5a7f382c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604254811180612d6e575060425415801590612d6e575080155b15612da5576040517faabd5a0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6044819055612726612a15565b73ffffffffffffffffffffffffffffffffffffffff8516612dff576040517fe6cd565400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff8881169190910291909117909155600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000169186169190911790556003612e868382613f82565b506004612e938282613f82565b5050600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9390931692909217909155505050565b5f54610100900460ff16612f76576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610d64565b603e80547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000951515959095027fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1694909417750100000000000000000000000000000000000000000093151593909302929092179092557fffffffff00000000000000000000000000000000000000000000000000000000165f90815260416020526040902055565b604254808210613072576040517fd244b30700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff166042838154811061309c5761309c613c94565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16146130f4576040517fd244b30700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83165f90815260436020526040812061312191613228565b604261312e6001836141ad565b8154811061313e5761313e613c94565b5f918252602090912001546042805473ffffffffffffffffffffffffffffffffffffffff909216918490811061317657613176613c94565b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060428054806131cc576131cc6141d3565b5f8281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055505050565b50805461323490613c49565b5f825580601f10613243575050565b601f0160209004905f5260205f209081019061325f9190613262565b50565b5b80821115613276575f8155600101613263565b5090565b80357fffffffff00000000000000000000000000000000000000000000000000000000811681146132a9575f5ffd5b919050565b5f602082840312156132be575f5ffd5b6132c78261327a565b9392505050565b5f5f83601f8401126132de575f5ffd5b50813567ffffffffffffffff8111156132f5575f5ffd5b60208301915083602082850101111561330c575f5ffd5b9250929050565b5f5f5f5f60408587031215613326575f5ffd5b843567ffffffffffffffff81111561333c575f5ffd5b613348878288016132ce565b909550935050602085013567ffffffffffffffff811115613367575f5ffd5b613373878288016132ce565b95989497509550505050565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081525f6132c7602083018461337f565b5f5f83601f8401126133ed575f5ffd5b50813567ffffffffffffffff811115613404575f5ffd5b6020830191508360208260051b850101111561330c575f5ffd5b5f5f5f5f60408587031215613431575f5ffd5b843567ffffffffffffffff811115613447575f5ffd5b613453878288016133dd565b909550935050602085013567ffffffffffffffff811115613472575f5ffd5b613373878288016133dd565b5f5f6040838503121561348f575f5ffd5b6134988361327a565b946020939093013593505050565b80357fffff000000000000000000000000000000000000000000000000000000000000811681146132a9575f5ffd5b5f5f604083850312156134e6575f5ffd5b6134ef836134a6565b91506134fd602084016134a6565b90509250929050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b828110156135a8577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0878603018452815173ffffffffffffffffffffffffffffffffffffffff81511686526020810151905060406020870152613592604087018261337f565b955050602093840193919091019060010161352c565b50929695505050505050565b5f602082840312156135c4575f5ffd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461325f575f5ffd5b80356132a9816135cb565b5f60208284031215613607575f5ffd5b81356132c7816135cb565b602080825282518282018190525f918401906040840190835b8181101561365f57835173ffffffffffffffffffffffffffffffffffffffff1683526020938401939092019160010161362b565b509095945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040805190810167ffffffffffffffff811182821017156136ba576136ba61366a565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156137075761370761366a565b604052919050565b5f67ffffffffffffffff8211156137285761372861366a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b5f6137666137618461370f565b6136c0565b9050828152838383011115613779575f5ffd5b828260208301375f602084830101529392505050565b5f82601f83011261379e575f5ffd5b6132c783833560208501613754565b5f602082840312156137bd575f5ffd5b813567ffffffffffffffff8111156137d3575f5ffd5b6137df8482850161378f565b949350505050565b801515811461325f575f5ffd5b80356132a9816137e7565b5f67ffffffffffffffff8211156138185761381861366a565b5060051b60200190565b5f82601f830112613831575f5ffd5b813561383f613761826137ff565b8082825260208201915060208360051b860101925085831115613860575f5ffd5b602085015b8381101561391257803567ffffffffffffffff811115613883575f5ffd5b860160408189037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00112156138b6575f5ffd5b6138be613697565b60208201356138cc816135cb565b8152604082013567ffffffffffffffff8111156138e7575f5ffd5b6138f68a60208386010161378f565b6020830152508085525050602083019250602081019050613865565b5095945050505050565b5f5f5f5f5f5f5f5f610100898b031215613934575f5ffd5b61393d896135ec565b975061394b60208a016135ec565b965061395960408a016135ec565b9550606089013567ffffffffffffffff811115613974575f5ffd5b6139808b828c0161378f565b955050608089013567ffffffffffffffff81111561399c575f5ffd5b6139a88b828c0161378f565b9450506139b760a08a016137f4565b925060c089013567ffffffffffffffff8111156139d2575f5ffd5b6139de8b828c01613822565b989b979a50959894979396929550929360e00135925050565b5f60208284031215613a07575f5ffd5b813567ffffffffffffffff811115613a1d575f5ffd5b8201601f81018413613a2d575f5ffd5b6137df84823560208401613754565b5f60208284031215613a4c575f5ffd5b813567ffffffffffffffff811681146132c7575f5ffd5b5f5f5f5f5f5f60c08789031215613a78575f5ffd5b8635613a83816135cb565b95506020870135613a93816135cb565b9450604087013563ffffffff81168114613aab575f5ffd5b93506060870135613abb816135cb565b9250608087013567ffffffffffffffff811115613ad6575f5ffd5b613ae289828a0161378f565b92505060a087013567ffffffffffffffff811115613afe575f5ffd5b613b0a89828a0161378f565b9150509295509295509295565b5f5f60208385031215613b28575f5ffd5b823567ffffffffffffffff811115613b3e575f5ffd5b613b4a858286016132ce565b90969095509350505050565b5f5f5f60608486031215613b68575f5ffd5b833567ffffffffffffffff811115613b7e575f5ffd5b8401601f81018613613b8e575f5ffd5b8035613b9c613761826137ff565b8082825260208201915060208360061b850101925088831115613bbd575f5ffd5b6020840193505b82841015613c0d576040848a031215613bdb575f5ffd5b613be3613697565b8435613bee816135cb565b8152602085810135818301529083526040909401939190910190613bc4565b9550505050602084013567ffffffffffffffff811115613c2b575f5ffd5b613c3786828701613822565b93969395505050506040919091013590565b600181811c90821680613c5d57607f821691505b6020821081036115eb577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613cf4575f5ffd5b83018035915067ffffffffffffffff821115613d0e575f5ffd5b60200191503681900382131561330c575f5ffd5b5f60208284031215613d32575f5ffd5b815167ffffffffffffffff811115613d48575f5ffd5b8201601f81018413613d58575f5ffd5b8051613d66613761826137ff565b8082825260208201915060208360051b850101925086831115613d87575f5ffd5b602084015b83811015613e7757805167ffffffffffffffff811115613daa575f5ffd5b85016040818a037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0011215613ddd575f5ffd5b613de5613697565b6020820151613df3816135cb565b8152604082015167ffffffffffffffff811115613e0e575f5ffd5b60208184010192505089601f830112613e25575f5ffd5b8151613e336137618261370f565b8181528b6020838601011115613e47575f5ffd5b8160208501602083015e5f6020838301015280602084015250508085525050602083019250602081019050613d8c565b509695505050505050565b5f60208284031215613e92575f5ffd5b815167ffffffffffffffff811115613ea8575f5ffd5b8201601f81018413613eb8575f5ffd5b8051613ec6613761826137ff565b8082825260208201915060208360051b850101925086831115613ee7575f5ffd5b6020840193505b82841015613f12578351613f01816135cb565b825260209384019390910190613eee565b9695505050505050565b5f60208284031215613f2c575f5ffd5b81516132c7816137e7565b601f82111561272657805f5260205f20601f840160051c81016020851015613f5c5750805b601f840160051c820191505b81811015613f7b575f8155600101613f68565b5050505050565b815167ffffffffffffffff811115613f9c57613f9c61366a565b613fb081613faa8454613c49565b84613f37565b6020601f821160018114614001575f8315613fcb5750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b178455613f7b565b5f848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b8281101561404e578785015182556020948501946001909201910161402e565b508482101561408a57868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b01905550565b5f602082840312156140a9575f5ffd5b5051919050565b5f82518060208501845e5f920191825250919050565b8281525f602082018354845f5260205f205f5b8281101561410d57815473ffffffffffffffffffffffffffffffffffffffff168452602090930192600191820191016140d9565b50919695505050505050565b606080825284549082018190525f8581526020812090916080840190835b8181101561416b57835473ffffffffffffffffffffffffffffffffffffffff16835260019384019360209093019201614137565b50506020840195909552505060400152919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8181038181111561134557611345614180565b8082018082111561134557611345614180565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea26469706673582212204c8d89fafb3caf45617cd4d4b662407a5f97b0708f57d8518c4bda54f7b3cad464736f6c634300081c0033000000000000000000000000580bda1e7a0cfae92fa7f6c20a3794f169ce3cfb000000000000000000000000455e53cbb86018ac2b8092fdcd39d8444affc3f60000000000000000000000002a3dd3eb832af982ec71669e178424b10dca2ede0000000000000000000000005132a183e9f3cb7c848b0aac5ae0c4f0491b7ab2000000000000000000000000046bb8bb98db4cecbb2929542686b74b516274b3
Deployed Bytecode
0x608060405234801561000f575f5ffd5b5060043610610441575f3560e01c80636e7fbce911610243578063c754c7ed11610148578063e75235b8116100c3578063effb847911610093578063f851a44011610079578063f851a44014610b03578063fc5014d614610b28578063fd7d249314610b4d575f5ffd5b8063effb847914610ad1578063f51f563a14610af0575f5ffd5b8063e75235b814610aa4578063e7a7ed0214610aac578063e90a340914610ac0578063efe6c9f41461049d575f5ffd5b8063cea5a4c011610118578063d02103ca116100fe578063d02103ca14610a2e578063d9c2853914610a55578063e46761c414610a7d575f5ffd5b8063cea5a4c014610a06578063cfa8ed4714610a0e575f5ffd5b8063c754c7ed146109bb578063c89e42df146109e3578063ca69e7dc146109f6578063cce7d0df146109fe575f5ffd5b80638c3d7301116101d8578063ab0475cf116101a8578063b3a326f71161018e578063b3a326f71461098d578063bdfbed7e146109a0578063be647d03146109b3575f5ffd5b8063ab0475cf14610953578063ada8f9191461097a575f5ffd5b80638c3d7301146108fe5780639ee4afa314610906578063a3c573eb14610919578063a8d31bd914610940575f5ffd5b806374f0b0c11161021357806374f0b0c114610887578063750a6e72146108a7578063759664d4146108af5780637df73e27146108eb575f5ffd5b80636e7fbce91461083a5780636ff512cc1461084157806371257022146108545780637388c43614610867575f5ffd5b806339b7ec1611610349578063527570f1116102de5780635ecaca2b116102ae5780636a55f66c116102945780636a55f66c146107ff5780636b8616ce146108125780636e05d2cd14610831575f5ffd5b80635ecaca2b146107cc578063697427f6146107ec575f5ffd5b8063527570f114610758578063542028d51461077857806354fd4d501461078057806359a03e0f146107b9575f5ffd5b806342cde4e81161031957806342cde4e8146106e657806345605267146106ef57806349b7b802146107285780634a5db0c11461074f575f5ffd5b806339b7ec16146106545780633c351e10146106745780633cbc795b146106945780633e1e0121146106d1575f5ffd5b806319451a8f116103d95780632c111c06116103a9578063349d40461161038f578063349d40461461061957806335acd6c21461062e57806336cd6b5b14610641575f5ffd5b80632c111c06146105f9578063314eb17b146104f6575f5ffd5b806319451a8f146104f65780631d0b435e14610509578063267822471461054d57806326f9b76d14610592575f5ffd5b80631489e707116104145780631489e7071461049d578063153c3b7f146104a557806315981b29146104b8578063188d9180146104c0575f5ffd5b806301fcf6a014610445578063052358be1461046b57806306e7666514610480578063107bf28c14610488575b5f5ffd5b6104586104533660046132ae565b505f90565b6040519081526020015b60405180910390f35b61047e610479366004613313565b610b55565b005b61047e610c1d565b610490610fb6565b60405161046291906133cb565b61047e611042565b61047e6104b336600461341e565b6110c5565b61047e611224565b603e546104e6907501000000000000000000000000000000000000000000900460ff1681565b6040519015158152602001610462565b61047e61050436600461347e565b611042565b61051c6105173660046134d5565b6112fb565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610462565b60015461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610462565b6105c86105a03660046132ae565b60101b7fffff0000000000000000000000000000000000000000000000000000000000001690565b6040517fffff0000000000000000000000000000000000000000000000000000000000009091168152602001610462565b60085461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b61062161134b565b6040516104629190613506565b61056d61063c3660046135b4565b6115f1565b61049061064f3660046135f7565b611626565b60465461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b60095461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b6009546106bc9074010000000000000000000000000000000000000000900463ffffffff1681565b60405163ffffffff9091168152602001610462565b6106d961163e565b6040516104629190613612565b61045860445481565b60075461070f9068010000000000000000900467ffffffffffffffff1681565b60405167ffffffffffffffff9091168152602001610462565b61056d7f0000000000000000000000005132a183e9f3cb7c848b0aac5ae0c4f0491b7ab281565b61045860455481565b60405461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b61049061177d565b60408051808201909152600681527f76312e302e3000000000000000000000000000000000000000000000000000006020820152610490565b6104906107c73660046137ad565b61178a565b603d5461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b61047e6107fa36600461391c565b6117ae565b61045861080d3660046139f7565b611a5a565b610458610820366004613a3c565b60066020525f908152604090205481565b61045860055481565b6105c85f81565b61047e61084f3660046135f7565b611ad4565b61047e610862366004613a63565b611b9d565b603f5461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b603e5461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b61045860ff81565b6104906040518060400160405280600681526020017f76312e302e30000000000000000000000000000000000000000000000000000081525081565b6104e66108f93660046135f7565b611bcf565b61047e611cdc565b61047e610914366004613b17565b611daf565b61056d7f0000000000000000000000002a3dd3eb832af982ec71669e178424b10dca2ede81565b61047e61094e3660046135f7565b611e82565b61056d7f000000000000000000000000046bb8bb98db4cecbb2929542686b74b516274b381565b61047e6109883660046135f7565b611f59565b61047e61099b3660046135f7565b612022565b61047e6109ae3660046135f7565b6121a8565b61047e6122c2565b60075461070f90700100000000000000000000000000000000900467ffffffffffffffff1681565b61047e6109f13660046137ad565b6123d3565b610458612465565b61045861251f565b6106bc600181565b60025461056d9073ffffffffffffffffffffffffffffffffffffffff1681565b61056d7f000000000000000000000000580bda1e7a0cfae92fa7f6c20a3794f169ce3cfb81565b610a68610a633660046139f7565b6125ee565b60408051928352602083019190915201610462565b61056d7f000000000000000000000000455e53cbb86018ac2b8092fdcd39d8444affc3f681565b610458612634565b60075461070f9067ffffffffffffffff1681565b6105c8610ace3660046132ae565b90565b610458610adf3660046132ae565b60416020525f908152604090205481565b61047e610afe366004613b56565b6126ca565b5f5461056d9062010000900473ffffffffffffffffffffffffffffffffffffffff1681565b603e546104e69074010000000000000000000000000000000000000000900460ff1681565b61047e61272b565b60465473ffffffffffffffffffffffffffffffffffffffff163314610ba6576040517fd0c34d9700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c1784848080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050604080516020601f880181900481028201810190925286815292508691508590819084018382808284375f9201919091525061282392505050565b50505050565b7f0000000000000000000000005132a183e9f3cb7c848b0aac5ae0c4f0491b7ab273ffffffffffffffffffffffffffffffffffffffff163314610c8c576040517fb9b3a2c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805460ff16907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815c168217905d505f54600290610100900460ff16158015610cdc57505f5460ff8083169116105b610d6d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff80841691909117610100178255905c16600114610ddd576040517fadc06ae700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f54603f80546201000090920473ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff000000000000000000000000000000000000000090921691909117905560038054610e3790613c49565b90505f03610e9b5760025460408051808201909152600681527f4e4f5f55524c00000000000000000000000000000000000000000000000000006020820152610e969173ffffffffffffffffffffffffffffffffffffffff16906128a0565b610f48565b60025460038054610f489273ffffffffffffffffffffffffffffffffffffffff169190610ec790613c49565b80601f0160208091040260200160405190810160405280929190818152602001828054610ef390613c49565b8015610f3e5780601f10610f1557610100808354040283529160200191610f3e565b820191905f5260205f20905b815481529060010190602001808311610f2157829003601f168201915b50505050506128a0565b6001604455610f55612a15565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498906020015b60405180910390a150565b60048054610fc390613c49565b80601f0160208091040260200160405190810160405280929190818152602001828054610fef90613c49565b801561103a5780601f106110115761010080835404028352916020019161103a565b820191905f5260205f20905b81548152906001019060200180831161101d57829003601f168201915b505050505081565b603f5473ffffffffffffffffffffffffffffffffffffffff163314611093576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fd37a223a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60465473ffffffffffffffffffffffffffffffffffffffff163314611116576040517fd0c34d9700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82818114611150576040517f059d0ac900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f5b8181101561121c5761121486868381811061116f5761116f613c94565b90506020028101906111819190613cc1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152508892508791508590508181106111c9576111c9613c94565b90506020028101906111db9190613cc1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061282392505050565b600101611152565b505050505050565b60405473ffffffffffffffffffffffffffffffffffffffff163314611275576040517f3ac87ac900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603f80546040805473ffffffffffffffffffffffffffffffffffffffff8082167fffffffffffffffffffffffff000000000000000000000000000000000000000080861682179096559490911682558151921680835260208301939093527f67c02ffba2f5329171ad235a360497af6ac3cfe82f1412866fbbf2dd3556ed3f9101610fab565b7fffff00000000000000000000000000000000000000000000000000000000000082167dffff00000000000000000000000000000000000000000000000000000000601083901c16175b92915050565b603e546060907501000000000000000000000000000000000000000000900460ff1615611424577f000000000000000000000000046bb8bb98db4cecbb2929542686b74b516274b373ffffffffffffffffffffffffffffffffffffffff1663349d40466040518163ffffffff1660e01b81526004015f60405180830381865afa1580156113da573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261141f9190810190613d22565b905090565b6042545f9067ffffffffffffffff8111156114415761144161366a565b60405190808252806020026020018201604052801561148657816020015b604080518082019091525f81526060602082015281526020019060019003908161145f5790505b5090505f5b6042548110156115eb576040518060400160405280604283815481106114b3576114b3613c94565b905f5260205f20015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200160435f6042858154811061150c5761150c613c94565b5f91825260208083209091015473ffffffffffffffffffffffffffffffffffffffff1683528201929092526040019020805461154790613c49565b80601f016020809104026020016040519081016040528092919081815260200182805461157390613c49565b80156115be5780601f10611595576101008083540402835291602001916115be565b820191905f5260205f20905b8154815290600101906020018083116115a157829003601f168201915b50505050508152508282815181106115d8576115d8613c94565b602090810291909101015260010161148b565b50919050565b60428181548110611600575f80fd5b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16905081565b60436020525f908152604090208054610fc390613c49565b603e546060907501000000000000000000000000000000000000000000900460ff1615611712577f000000000000000000000000046bb8bb98db4cecbb2929542686b74b516274b373ffffffffffffffffffffffffffffffffffffffff16633e1e01216040518163ffffffff1660e01b81526004015f60405180830381865afa1580156116cd573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261141f9190810190613e82565b604280548060200260200160405190810160405280929190818152602001828054801561177357602002820191905f5260205f20905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311611748575b5050505050905090565b60038054610fc390613c49565b805160208183018101805160478252928201919093012091528054610fc390613c49565b603f5473ffffffffffffffffffffffffffffffffffffffff1633146117ff576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805460ff16907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00815c168217905d505f54600290610100900460ff1615801561184f57505f5460ff8083169116105b6118db576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610d64565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001660ff80841691909117610100178255905c1615611949576040517fadc06ae700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61195a89898989895f8a8180612a99565b83156119ac578251151580611970575060445415155b156119a7576040517f996c343000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6119f2565b604080515f808252602082019092526119f2916119ea565b604080518082019091525f80825260208201528152602001906001900390816119c45790505b508484612bc1565b5f80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff16905560405160ff821681527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a1505050505050505050565b5f5f611a6461251f565b90505f5f611a71856125ee565b6040517c010000000000000000000000000000000000000000000000000000000060208201526024810183905260448101829052606481018690529193509150608401604051602081830303815290604052805190602001209350505050919050565b5f5462010000900473ffffffffffffffffffffffffffffffffffffffff163314611b2a576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527ff54144f9611984021529f814a1cb6a41e22c58351510a0d9f7e822618abb9cc090602001610fab565b6040517ff57ac68300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603e545f907501000000000000000000000000000000000000000000900460ff1615611ca3576040517f7df73e2700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301527f000000000000000000000000046bb8bb98db4cecbb2929542686b74b516274b31690637df73e2790602401602060405180830381865afa158015611c7f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113459190613f1c565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526043602052604081208054611cd290613c49565b9050119050919050565b60015473ffffffffffffffffffffffffffffffffffffffff163314611d2d576040517fd1ec4b2300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001545f80547fffffffffffffffffffff0000000000000000000000000000000000000000ffff1673ffffffffffffffffffffffffffffffffffffffff9092166201000081029290921790556040519081527f056dc487bbf0795d0bbb1b4f0af523a855503cff740bfb4d5475f7a90c091e8e906020015b60405180910390a1565b7f0000000000000000000000005132a183e9f3cb7c848b0aac5ae0c4f0491b7ab273ffffffffffffffffffffffffffffffffffffffff163314611e1e576040517fb9b3a2c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8015611e56576040517f3063965400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fc118263690a4306c74bd1bc80b55962addc2d9e61619ac0b2c2883badbbd01d8905f90a15050565b603f5473ffffffffffffffffffffffffffffffffffffffff163314611ed3576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6046805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff000000000000000000000000000000000000000083168117909355604080519190921680825260208201939093527f82ae2ec69f24a6de4517a5a45d4983651b578b3d8dc9262af5e352572fc64373910160405180910390a15050565b5f5462010000900473ffffffffffffffffffffffffffffffffffffffff163314611faf576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527fa5b56b7906fd0a20e3f35120dd8343db1e12e037a6c90111c7e42885e82a1ce690602001610fab565b7f0000000000000000000000005132a183e9f3cb7c848b0aac5ae0c4f0491b7ab273ffffffffffffffffffffffffffffffffffffffff163314612091576040517fb9b3a2c800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603f5473ffffffffffffffffffffffffffffffffffffffff16156120e1576040517f257bb0bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811661212e576040517fd6bdac3f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603f80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8316908117909155604080515f815260208101929092527f67c02ffba2f5329171ad235a360497af6ac3cfe82f1412866fbbf2dd3556ed3f9101610fab565b603f5473ffffffffffffffffffffffffffffffffffffffff1633146121f9576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8116612246576040517ff6b2911f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182178355603f5483519116815260208101919091527fa3d8e5d045432398be30f83ce7c35a7bfc220c1b66cc5bf3f4dd4d539d93fab69101610fab565b603f5473ffffffffffffffffffffffffffffffffffffffff163314612313576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603e547501000000000000000000000000000000000000000000900460ff1615612369576040517f278d998800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603e80547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1675010000000000000000000000000000000000000000001790556040517f67ec953bdc8546ede08f8ee91e5205a1d1814e126cb8f5d00a918ddb1eaa292b905f90a1565b5f5462010000900473ffffffffffffffffffffffffffffffffffffffff163314612429576040517f4755657900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60036124358282613f82565b507f6b8f723a4c7a5335cafae8a598a0aa0301be1387c037dccc085b62add6448b2081604051610fab91906133cb565b603e545f907501000000000000000000000000000000000000000000900460ff1615612518577f000000000000000000000000046bb8bb98db4cecbb2929542686b74b516274b373ffffffffffffffffffffffffffffffffffffffff1663ca69e7dc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124f4573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061141f9190614099565b5060425490565b603e545f907501000000000000000000000000000000000000000000900460ff16156125ae577f000000000000000000000000046bb8bb98db4cecbb2929542686b74b516274b373ffffffffffffffffffffffffffffffffffffffff1663cce7d0df6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124f4573d5f5f3e3d5ffd5b6045546125e7576040517fdd41f1ef00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060455490565b5f5f82515f1461262a576040517f3063965400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505f928392509050565b603e545f907501000000000000000000000000000000000000000000900460ff16156126c3577f000000000000000000000000046bb8bb98db4cecbb2929542686b74b516274b373ffffffffffffffffffffffffffffffffffffffff1663e75235b86040518163ffffffff1660e01b8152600401602060405180830381865afa1580156124f4573d5f5f3e3d5ffd5b5060445490565b603f5473ffffffffffffffffffffffffffffffffffffffff16331461271b576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612726838383612bc1565b505050565b603f5473ffffffffffffffffffffffffffffffffffffffff16331461277c576040517f660a7ce500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603e547501000000000000000000000000000000000000000000900460ff166127d1576040517f5aa930a000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b603e80547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1690556040517f4c75580a56c734245a7418eb07d8a311e1bff79f982fed747da3589630e414be905f90a1565b8060478360405161283491906140b0565b9081526020016040518091039020908161284e9190613f82565b508160405161285d91906140b0565b60405180910390207f2779f9edd5ec4e0a99bffdea4008c8b979200959062a2bf00142acb939ca1b648260405161289491906133cb565b60405180910390a25050565b73ffffffffffffffffffffffffffffffffffffffff82166128ed576040517f7b3a0df600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80515f03612927576040517f8715f5fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82165f908152604360205260408120805461295690613c49565b90501115612990576040517f38615ecc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60428054600181019091557f38dfe4635b27babeca8be38d3b448cb5161a639b899a14825ba9c8d7892eb8c30180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff84169081179091555f9081526043602052604090206127268282613f82565b6044546042604051602001612a2b9291906140c6565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052805160209091012060458190556044547f66d7b0647fdd512b69cbf4f8e1ce8068bfe0b236168e2704ba13b07425eaa74392611da59260429291614119565b5f54610100900460ff16612b2f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610d64565b73ffffffffffffffffffffffffffffffffffffffff89161580612b66575073ffffffffffffffffffffffffffffffffffffffff8816155b15612b9d576040517ff6b2911f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612baa8989898989612db2565b612bb684848484612ee0565b505050505050505050565b600183511115612c69575f5b60018451612bdb91906141ad565b811015612c675783612bee8260016141c0565b81518110612bfe57612bfe613c94565b602002602001015160200151848281518110612c1c57612c1c613c94565b60200260200101516020015111612c5f576040517fb9a11d3100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600101612bcd565b505b5f5b8351811015612cbf57612cb7848281518110612c8957612c89613c94565b60200260200101515f0151858381518110612ca657612ca6613c94565b602002602001015160200151613036565b600101612c6b565b505f5b8251811015612d1657612d0e838281518110612ce057612ce0613c94565b60200260200101515f0151848381518110612cfd57612cfd613c94565b6020026020010151602001516128a0565b600101612cc2565b5060425460ff1015612d54576040517f5a7f382c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604254811180612d6e575060425415801590612d6e575080155b15612da5576040517faabd5a0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6044819055612726612a15565b73ffffffffffffffffffffffffffffffffffffffff8516612dff576040517fe6cd565400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff8881169190910291909117909155600280547fffffffffffffffffffffffff0000000000000000000000000000000000000000169186169190911790556003612e868382613f82565b506004612e938282613f82565b5050600980547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9390931692909217909155505050565b5f54610100900460ff16612f76576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610d64565b603e80547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000951515959095027fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1694909417750100000000000000000000000000000000000000000093151593909302929092179092557fffffffff00000000000000000000000000000000000000000000000000000000165f90815260416020526040902055565b604254808210613072576040517fd244b30700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff166042838154811061309c5761309c613c94565b5f9182526020909120015473ffffffffffffffffffffffffffffffffffffffff16146130f4576040517fd244b30700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff83165f90815260436020526040812061312191613228565b604261312e6001836141ad565b8154811061313e5761313e613c94565b5f918252602090912001546042805473ffffffffffffffffffffffffffffffffffffffff909216918490811061317657613176613c94565b905f5260205f20015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060428054806131cc576131cc6141d3565b5f8281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169055019055505050565b50805461323490613c49565b5f825580601f10613243575050565b601f0160209004905f5260205f209081019061325f9190613262565b50565b5b80821115613276575f8155600101613263565b5090565b80357fffffffff00000000000000000000000000000000000000000000000000000000811681146132a9575f5ffd5b919050565b5f602082840312156132be575f5ffd5b6132c78261327a565b9392505050565b5f5f83601f8401126132de575f5ffd5b50813567ffffffffffffffff8111156132f5575f5ffd5b60208301915083602082850101111561330c575f5ffd5b9250929050565b5f5f5f5f60408587031215613326575f5ffd5b843567ffffffffffffffff81111561333c575f5ffd5b613348878288016132ce565b909550935050602085013567ffffffffffffffff811115613367575f5ffd5b613373878288016132ce565b95989497509550505050565b5f81518084528060208401602086015e5f6020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081525f6132c7602083018461337f565b5f5f83601f8401126133ed575f5ffd5b50813567ffffffffffffffff811115613404575f5ffd5b6020830191508360208260051b850101111561330c575f5ffd5b5f5f5f5f60408587031215613431575f5ffd5b843567ffffffffffffffff811115613447575f5ffd5b613453878288016133dd565b909550935050602085013567ffffffffffffffff811115613472575f5ffd5b613373878288016133dd565b5f5f6040838503121561348f575f5ffd5b6134988361327a565b946020939093013593505050565b80357fffff000000000000000000000000000000000000000000000000000000000000811681146132a9575f5ffd5b5f5f604083850312156134e6575f5ffd5b6134ef836134a6565b91506134fd602084016134a6565b90509250929050565b5f602082016020835280845180835260408501915060408160051b8601019250602086015f5b828110156135a8577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0878603018452815173ffffffffffffffffffffffffffffffffffffffff81511686526020810151905060406020870152613592604087018261337f565b955050602093840193919091019060010161352c565b50929695505050505050565b5f602082840312156135c4575f5ffd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461325f575f5ffd5b80356132a9816135cb565b5f60208284031215613607575f5ffd5b81356132c7816135cb565b602080825282518282018190525f918401906040840190835b8181101561365f57835173ffffffffffffffffffffffffffffffffffffffff1683526020938401939092019160010161362b565b509095945050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040805190810167ffffffffffffffff811182821017156136ba576136ba61366a565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156137075761370761366a565b604052919050565b5f67ffffffffffffffff8211156137285761372861366a565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b5f6137666137618461370f565b6136c0565b9050828152838383011115613779575f5ffd5b828260208301375f602084830101529392505050565b5f82601f83011261379e575f5ffd5b6132c783833560208501613754565b5f602082840312156137bd575f5ffd5b813567ffffffffffffffff8111156137d3575f5ffd5b6137df8482850161378f565b949350505050565b801515811461325f575f5ffd5b80356132a9816137e7565b5f67ffffffffffffffff8211156138185761381861366a565b5060051b60200190565b5f82601f830112613831575f5ffd5b813561383f613761826137ff565b8082825260208201915060208360051b860101925085831115613860575f5ffd5b602085015b8381101561391257803567ffffffffffffffff811115613883575f5ffd5b860160408189037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00112156138b6575f5ffd5b6138be613697565b60208201356138cc816135cb565b8152604082013567ffffffffffffffff8111156138e7575f5ffd5b6138f68a60208386010161378f565b6020830152508085525050602083019250602081019050613865565b5095945050505050565b5f5f5f5f5f5f5f5f610100898b031215613934575f5ffd5b61393d896135ec565b975061394b60208a016135ec565b965061395960408a016135ec565b9550606089013567ffffffffffffffff811115613974575f5ffd5b6139808b828c0161378f565b955050608089013567ffffffffffffffff81111561399c575f5ffd5b6139a88b828c0161378f565b9450506139b760a08a016137f4565b925060c089013567ffffffffffffffff8111156139d2575f5ffd5b6139de8b828c01613822565b989b979a50959894979396929550929360e00135925050565b5f60208284031215613a07575f5ffd5b813567ffffffffffffffff811115613a1d575f5ffd5b8201601f81018413613a2d575f5ffd5b6137df84823560208401613754565b5f60208284031215613a4c575f5ffd5b813567ffffffffffffffff811681146132c7575f5ffd5b5f5f5f5f5f5f60c08789031215613a78575f5ffd5b8635613a83816135cb565b95506020870135613a93816135cb565b9450604087013563ffffffff81168114613aab575f5ffd5b93506060870135613abb816135cb565b9250608087013567ffffffffffffffff811115613ad6575f5ffd5b613ae289828a0161378f565b92505060a087013567ffffffffffffffff811115613afe575f5ffd5b613b0a89828a0161378f565b9150509295509295509295565b5f5f60208385031215613b28575f5ffd5b823567ffffffffffffffff811115613b3e575f5ffd5b613b4a858286016132ce565b90969095509350505050565b5f5f5f60608486031215613b68575f5ffd5b833567ffffffffffffffff811115613b7e575f5ffd5b8401601f81018613613b8e575f5ffd5b8035613b9c613761826137ff565b8082825260208201915060208360061b850101925088831115613bbd575f5ffd5b6020840193505b82841015613c0d576040848a031215613bdb575f5ffd5b613be3613697565b8435613bee816135cb565b8152602085810135818301529083526040909401939190910190613bc4565b9550505050602084013567ffffffffffffffff811115613c2b575f5ffd5b613c3786828701613822565b93969395505050506040919091013590565b600181811c90821680613c5d57607f821691505b6020821081036115eb577f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f5f83357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613cf4575f5ffd5b83018035915067ffffffffffffffff821115613d0e575f5ffd5b60200191503681900382131561330c575f5ffd5b5f60208284031215613d32575f5ffd5b815167ffffffffffffffff811115613d48575f5ffd5b8201601f81018413613d58575f5ffd5b8051613d66613761826137ff565b8082825260208201915060208360051b850101925086831115613d87575f5ffd5b602084015b83811015613e7757805167ffffffffffffffff811115613daa575f5ffd5b85016040818a037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0011215613ddd575f5ffd5b613de5613697565b6020820151613df3816135cb565b8152604082015167ffffffffffffffff811115613e0e575f5ffd5b60208184010192505089601f830112613e25575f5ffd5b8151613e336137618261370f565b8181528b6020838601011115613e47575f5ffd5b8160208501602083015e5f6020838301015280602084015250508085525050602083019250602081019050613d8c565b509695505050505050565b5f60208284031215613e92575f5ffd5b815167ffffffffffffffff811115613ea8575f5ffd5b8201601f81018413613eb8575f5ffd5b8051613ec6613761826137ff565b8082825260208201915060208360051b850101925086831115613ee7575f5ffd5b6020840193505b82841015613f12578351613f01816135cb565b825260209384019390910190613eee565b9695505050505050565b5f60208284031215613f2c575f5ffd5b81516132c7816137e7565b601f82111561272657805f5260205f20601f840160051c81016020851015613f5c5750805b601f840160051c820191505b81811015613f7b575f8155600101613f68565b5050505050565b815167ffffffffffffffff811115613f9c57613f9c61366a565b613fb081613faa8454613c49565b84613f37565b6020601f821160018114614001575f8315613fcb5750848201515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600385901b1c1916600184901b178455613f7b565b5f848152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08516915b8281101561404e578785015182556020948501946001909201910161402e565b508482101561408a57868401517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b60f8161c191681555b50505050600190811b01905550565b5f602082840312156140a9575f5ffd5b5051919050565b5f82518060208501845e5f920191825250919050565b8281525f602082018354845f5260205f205f5b8281101561410d57815473ffffffffffffffffffffffffffffffffffffffff168452602090930192600191820191016140d9565b50919695505050505050565b606080825284549082018190525f8581526020812090916080840190835b8181101561416b57835473ffffffffffffffffffffffffffffffffffffffff16835260019384019360209093019201614137565b50506020840195909552505060400152919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b8181038181111561134557611345614180565b8082018082111561134557611345614180565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603160045260245ffdfea26469706673582212204c8d89fafb3caf45617cd4d4b662407a5f97b0708f57d8518c4bda54f7b3cad464736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000580bda1e7a0cfae92fa7f6c20a3794f169ce3cfb000000000000000000000000455e53cbb86018ac2b8092fdcd39d8444affc3f60000000000000000000000002a3dd3eb832af982ec71669e178424b10dca2ede0000000000000000000000005132a183e9f3cb7c848b0aac5ae0c4f0491b7ab2000000000000000000000000046bb8bb98db4cecbb2929542686b74b516274b3
-----Decoded View---------------
Arg [0] : _globalExitRootManager (address): 0x580bda1e7A0CFAe92Fa7F6c20A3794F169CE3CFb
Arg [1] : _pol (address): 0x455e53CBB86018Ac2B8092FdCd39d8444aFFC3F6
Arg [2] : _bridgeAddress (address): 0x2a3DD3EB832aF982ec71669E178424b10Dca2EDe
Arg [3] : _rollupManager (address): 0x5132A183E9F3CB7C848b0AAC5Ae0c4f0491B7aB2
Arg [4] : _aggLayerGateway (address): 0x046Bb8bb98Db4ceCbB2929542686B74b516274b3
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000580bda1e7a0cfae92fa7f6c20a3794f169ce3cfb
Arg [1] : 000000000000000000000000455e53cbb86018ac2b8092fdcd39d8444affc3f6
Arg [2] : 0000000000000000000000002a3dd3eb832af982ec71669e178424b10dca2ede
Arg [3] : 0000000000000000000000005132a183e9f3cb7c848b0aac5ae0c4f0491b7ab2
Arg [4] : 000000000000000000000000046bb8bb98db4cecbb2929542686b74b516274b3
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.