Source Code
Overview
S Balance
S Value
$1.22 (@ $0.07/S)Latest 25 from a total of 287 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Receive V3 | 61034791 | 21 hrs ago | IN | 0 S | 0.1451786 | ||||
| Receive V3 | 61034396 | 21 hrs ago | IN | 0 S | 0.14500579 | ||||
| Receive V3 | 61024182 | 25 hrs ago | IN | 0 S | 0.08251034 | ||||
| Receive V3 | 60978299 | 40 hrs ago | IN | 0 S | 0.08586099 | ||||
| Receive V3 | 60961753 | 46 hrs ago | IN | 0 S | 0.14396756 | ||||
| Receive V3 | 60947181 | 2 days ago | IN | 0 S | 0.08147276 | ||||
| Receive V3 | 60943455 | 2 days ago | IN | 0 S | 0.27544115 | ||||
| Receive V3 | 60918965 | 2 days ago | IN | 0 S | 0.28138423 | ||||
| Receive V3 | 60907597 | 2 days ago | IN | 0 S | 0.28051661 | ||||
| Receive V3 | 60874193 | 3 days ago | IN | 0 S | 0.14535026 | ||||
| Receive V3 | 60824442 | 3 days ago | IN | 0 S | 0.13693812 | ||||
| Receive V3 | 60818947 | 3 days ago | IN | 0 S | 0.1439697 | ||||
| Receive V3 | 60808591 | 4 days ago | IN | 0 S | 0.23526393 | ||||
| Receive V3 | 60791483 | 4 days ago | IN | 0 S | 0.13936202 | ||||
| Receive V3 | 60788898 | 4 days ago | IN | 0 S | 0.13953362 | ||||
| Receive V3 | 60785230 | 4 days ago | IN | 0 S | 0.25426285 | ||||
| Receive V3 | 60768382 | 4 days ago | IN | 0 S | 0.14604304 | ||||
| Receive V3 | 60768336 | 4 days ago | IN | 0 S | 0.13918674 | ||||
| Receive V3 | 60708345 | 5 days ago | IN | 0 S | 0.14500552 | ||||
| Receive V3 | 60706829 | 5 days ago | IN | 0 S | 0.16658147 | ||||
| Receive V3 | 60695693 | 5 days ago | IN | 0 S | 0.2460073 | ||||
| Receive V3 | 60680286 | 5 days ago | IN | 0 S | 0.1451764 | ||||
| Receive V3 | 60659584 | 6 days ago | IN | 0 S | 0.11865573 | ||||
| Receive V3 | 60659170 | 6 days ago | IN | 0 S | 0.14638849 | ||||
| Receive V3 | 60658727 | 6 days ago | IN | 0 S | 0.14604084 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 61070431 | 4 hrs ago | 0.10228049 S | ||||
| 61058958 | 9 hrs ago | 0.02843842 S | ||||
| 61041640 | 17 hrs ago | 0.02773411 S | ||||
| 61034797 | 21 hrs ago | 0.02727324 S | ||||
| 61034751 | 21 hrs ago | 0.02769766 S | ||||
| 61034441 | 21 hrs ago | 0.05544491 S | ||||
| 61025951 | 25 hrs ago | 0.00155825 S | ||||
| 61024427 | 25 hrs ago | 0.01694835 S | ||||
| 61024167 | 25 hrs ago | 0.02887733 S | ||||
| 61012452 | 29 hrs ago | 0.1181202 S | ||||
| 61007348 | 31 hrs ago | 0.03030678 S | ||||
| 60998665 | 33 hrs ago | 0.03057246 S | ||||
| 60994461 | 34 hrs ago | 0.02429403 S | ||||
| 60977842 | 40 hrs ago | 0.01706079 S | ||||
| 60961794 | 46 hrs ago | 0.04736242 S | ||||
| 60958569 | 47 hrs ago | 0.03437566 S | ||||
| 60947433 | 2 days ago | 0.01610441 S | ||||
| 60943487 | 2 days ago | 0.06514918 S | ||||
| 60939849 | 2 days ago | 0.07795257 S | ||||
| 60918991 | 2 days ago | 0.10080648 S | ||||
| 60909378 | 2 days ago | 0.05171516 S | ||||
| 60907628 | 2 days ago | 0.06527889 S | ||||
| 60896429 | 2 days ago | 0.03436666 S | ||||
| 60888303 | 3 days ago | 0.02738767 S | ||||
| 60882150 | 3 days ago | 0.03441214 S |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
GovBridgeV2
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) Eywa.Fi, 2021-2025 - all rights reserved
pragma solidity ^0.8.17;
import "./BridgeV3.sol";
contract GovBridgeV2 is BridgeV3 {
/// @dev current protocol version
uint64 public protocolVersion;
/// @dev next protocol version, will be accepted fron next epoch
uint64 public nextProtocolVersion;
/// @dev current epoch start time
uint256 public epochStartTime;
/// @dev epoch min duration
uint256 public epochMinDuration;
/// @dev last request epoch update time
uint256 public lastRequestEpochUpdateTime;
/// @dev epoch min request update duration
uint256 public epochMinRequestUpdateDuration;
/// @dev node registry contract address
address public nodeRegistry;
event EpochUpdateRequested(uint32 currentEpochNum, uint64 protocolVersion);
event ProtocolVersionUpdateRequested(uint64 version, uint64 nextVersion);
event NodeRegistrySet(address nodeRegistry);
event EpochMinDurationSet(uint256 epochMinDuration);
event EpochMinRequestUpdateDurationSet(uint256 epochMinRequestUpdateDuration);
constructor(string memory tag_) BridgeV3(tag_) {
protocolVersion = 1;
nextProtocolVersion = 1;
epochMinDuration = 2 hours;
epochMinRequestUpdateDuration = 30 minutes;
}
/**
* @dev Changes node registry address.
*
* Controlled by DAO and\or multisig (3 out of 5, Gnosis Safe).
*/
function setNodeRegistry(address nodeRegistry_) external onlyRole(DEFAULT_ADMIN_ROLE) {
require(nodeRegistry_ != address(0), "GovBridge: zero address given");
nodeRegistry = nodeRegistry_;
emit NodeRegistrySet(nodeRegistry);
}
/**
* @dev Request to update epoch. Anyone may call it after epochMinDuration passed.
*/
function requestEpochUpdate() external {
require(block.timestamp > lastRequestEpochUpdateTime, "GovBridge: not enough time after retry");
require(block.timestamp > epochStartTime + epochMinDuration, "GovBridge: not enough time after epoch");
lastRequestEpochUpdateTime = block.timestamp + epochMinRequestUpdateDuration;
emit EpochUpdateRequested(currentEpoch.epochNum, protocolVersion);
}
/**
* @dev Request to update protocol version.
*
* Controlled by Operator.
*/
function requestProtocolVersionUpdate(uint64 version) external onlyRole(OPERATOR_ROLE) {
require(version - 1 == protocolVersion, "GovBridge: wrong protocol version");
nextProtocolVersion = version;
emit ProtocolVersionUpdateRequested(version, nextProtocolVersion);
}
/**
* @dev Set epoch min duration. Only DAO may call this.
*
* Controlled by DAO and\or multisig (3 out of 5, Gnosis Safe).
*/
function setEpochMinDuration(uint256 epochMinDuration_) external onlyRole(DEFAULT_ADMIN_ROLE) {
epochMinDuration = epochMinDuration_;
emit EpochMinDurationSet(epochMinDuration);
}
/**
* @dev Set epoch min request update duration. Only DAO may call this.
*
* Controlled by DAO and\or multisig (3 out of 5, Gnosis Safe).
*/
function setEpochMinRequestUpdateDuration(uint256 epochMinRequestUpdateDuration_) external onlyRole(DEFAULT_ADMIN_ROLE) {
epochMinRequestUpdateDuration = epochMinRequestUpdateDuration_;
emit EpochMinRequestUpdateDurationSet(epochMinRequestUpdateDuration);
}
/**
* @dev Hook on start new epoch.
*/
function onEpochStart(uint64 protocolVersion_) internal override {
uint64 prevProtocolVersion = protocolVersion;
if (protocolVersion_ != 0) {
protocolVersion = protocolVersion_;
} else {
protocolVersion = nextProtocolVersion;
}
require(protocolVersion >= prevProtocolVersion, "GovBridge: wrong protocol version");
epochStartTime = block.timestamp;
emit EpochUpdated(abi.encode(currentEpoch.publicKey), currentEpoch.epochNum, protocolVersion);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol)
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual override returns (bool) {
return _roles[role].members[account];
}
/**
* @dev Revert with a standard message if `_msgSender()` is missing `role`.
* Overriding this function changes the behavior of the {onlyRole} modifier.
*
* Format of the revert message is described in {_checkRole}.
*
* _Available since v4.6._
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(account),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* May emit a {RoleGranted} event.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol)
pragma solidity ^0.8.0;
import "./IAccessControlEnumerable.sol";
import "./AccessControl.sol";
import "../utils/structs/EnumerableSet.sol";
/**
* @dev Extension of {AccessControl} that allows enumerating the members of each role.
*/
abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {
using EnumerableSet for EnumerableSet.AddressSet;
mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) {
return _roleMembers[role].at(index);
}
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) {
return _roleMembers[role].length();
}
/**
* @dev Overload {_grantRole} to track enumerable memberships
*/
function _grantRole(bytes32 role, address account) internal virtual override {
super._grantRole(role, account);
_roleMembers[role].add(account);
}
/**
* @dev Overload {_revokeRole} to track enumerable memberships
*/
function _revokeRole(bytes32 role, address account) internal virtual override {
super._revokeRole(role, account);
_roleMembers[role].remove(account);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
/**
* @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
*/
interface IAccessControlEnumerable is IAccessControl {
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) external view returns (address);
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: Unlicense /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ pragma solidity >=0.8.0 <0.9.0; library BytesLib { function concat( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore(0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. )) } return tempBytes; } function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and( fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 ), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { // We're using the unchecked block below because otherwise execution ends // with the native overflow error code. unchecked { require(_length + 31 >= _length, "slice_overflow"); } require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) { require(_bytes.length >= _start + 1 , "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equalStorage( bytes storage _preBytes, bytes memory _postBytes ) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for {} eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } }
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) Eywa.Fi, 2021-2025 - all rights reserved
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/access/AccessControlEnumerable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../interfaces/IBridgeV3.sol";
import "../interfaces/IOracle.sol";
import "../interfaces/IReceiver.sol";
import "../utils/Block.sol";
import "../utils/Bls.sol";
import "../utils/Merkle.sol";
contract BridgeV3 is IBridgeV3, AccessControlEnumerable, ReentrancyGuard {
using Address for address;
using Bls for Bls.Epoch;
/// @dev gate keeper role id
bytes32 public constant GATEKEEPER_ROLE = keccak256("GATEKEEPER_ROLE");
/// @dev validator role id
bytes32 public constant VALIDATOR_ROLE = keccak256("VALIDATOR_ROLE");
/// @dev operator role id
bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE");
/// @dev receiver that store thresholds
address public receiver;
/// @dev priceOracle that store prices for execution
address public priceOracle;
/// @dev human readable version
string public version;
/// @dev human readable tag
string public tag;
/// @dev current state Active\Inactive
State public state;
/// @dev received request IDs
mapping(bytes32 => bool) public requestIdChecker;
// current epoch
Bls.Epoch internal currentEpoch;
// previous epoch
Bls.Epoch internal previousEpoch;
event EpochUpdated(bytes key, uint32 epochNum, uint64 protocolVersion);
event RequestSent(
bytes32 requestId,
bytes data,
address to,
uint64 chainIdTo
);
event StateSet(State state);
event ReceiverSet(address receiver);
event PriceOracleSet(address priceOracle);
event ValueWithdrawn(address to, uint256 amount);
event GasPaid(bytes32 requestId, uint32 gasAmount);
constructor(string memory tag_) {
_grantRole(DEFAULT_ADMIN_ROLE, _msgSender());
version = "2.2.3";
state = State.Inactive;
tag = tag_;
}
/**
* @dev Get current epoch.
*/
function getCurrentEpoch() public view returns (bytes memory, uint8, uint32) {
return (abi.encode(currentEpoch.publicKey), currentEpoch.participantsCount, currentEpoch.epochNum);
}
/**
* @dev Get previous epoch.
*/
function getPreviousEpoch() public view returns (bytes memory, uint8, uint32) {
return (abi.encode(previousEpoch.publicKey), previousEpoch.participantsCount, previousEpoch.epochNum);
}
/**
* @dev Updates current epoch.
*
* @param params ReceiveParams struct.
*/
function updateEpoch(ReceiveParams calldata params) external onlyRole(VALIDATOR_ROLE) {
// TODO ensure that new epoch really next one after previous (by hash)
bytes memory payload = Merkle.prove(params.merkleProof, Block.txRootHash(params.blockHeader));
(uint64 newEpochProtocolVersion, uint32 newEpochNum, bytes memory newKey, uint8 newParticipantsCount) = Block
.decodeEpochUpdate(payload);
require(currentEpoch.epochNum + 1 == newEpochNum, "Bridge: wrong epoch number");
// TODO remove if when resetEpoch will be removed
if (currentEpoch.isSet()) {
verifyEpoch(currentEpoch, params);
rotateEpoch();
}
// TODO ensure that new epoch really next one after previous (prev hash + params.blockHeader)
bytes32 newHash = sha256(params.blockHeader);
currentEpoch.update(newKey, newParticipantsCount, newEpochNum, newHash);
onEpochStart(newEpochProtocolVersion);
}
/**
* @dev Forcefully reset epoch on all chains.
*
* Controlled by operator. Should be removed at PoS stage.
*/
function resetEpoch() public onlyRole(OPERATOR_ROLE) {
// TODO consider to remove any possible manipulations from protocol
if (currentEpoch.isSet()) {
rotateEpoch();
currentEpoch.epochNum = previousEpoch.epochNum + 1;
} else {
currentEpoch.epochNum = currentEpoch.epochNum + 1;
}
onEpochStart(0);
}
/**
* @dev Send crosschain request v3.
*
* @param params struct with requestId, data, receiver and opposite cahinId
* @param sender address to where send params
* @param nonce unique nonce for send
* @param options additional params for send
*/
function sendV3(
SendParams calldata params,
address sender,
uint256 nonce,
bytes memory options
) external payable onlyRole(GATEKEEPER_ROLE) {
require(state == State.Active, "Bridge: state inactive");
require(previousEpoch.isSet() || currentEpoch.isSet(), "Bridge: epoch not set");
address to = address(uint160(uint256(params.to)));
emit RequestSent(
params.requestId,
params.data,
to,
params.chainIdTo
);
emit GasPaid(params.requestId, abi.decode(options, (uint32)));
}
/**
* @dev Estimate crosschain request v3.
*
* @param params struct with requestId, data, receiver and opposite cahinId
* @param sender address to where send params
* @param options additional params for send
*/
function estimateGasFee(
SendParams calldata params,
address sender,
bytes memory options
) public view returns (uint256) {
uint32 gasExecute = abi.decode(options, (uint32));
(uint256 fee,) = IOracle(priceOracle).estimateFeeByChain(
params.chainIdTo,
params.data.length,
gasExecute
);
return fee;
}
/**
* @dev Withdraw value from this contract.
*
* @param value_ Amount of value
*/
function withdrawValue(uint256 value_) external onlyRole(DEFAULT_ADMIN_ROLE) {
(bool success, ) = msg.sender.call{value: value_}("");
require(success, "BridgeV3: failed to send Ether");
emit ValueWithdrawn(msg.sender, value_);
}
/**
* @dev Receive crosschain request v3.
*
* @param params array with ReceiveParams structs.
*/
function receiveV3(ReceiveParams[] calldata params) external override onlyRole(VALIDATOR_ROLE) nonReentrant returns (bool) {
require(state != State.Inactive, "Bridge: state inactive");
for (uint256 i = 0; i < params.length; ++i) {
bytes32 epochHash = Block.epochHash(params[i].blockHeader);
// verify the block signature
if (epochHash == currentEpoch.epochHash) {
require(currentEpoch.isSet(), "Bridge: epoch not set");
verifyEpoch(currentEpoch, params[i]);
} else if (epochHash == previousEpoch.epochHash) {
require(previousEpoch.isSet(), "Bridge: epoch not set");
verifyEpoch(previousEpoch, params[i]);
} else {
revert("Bridge: wrong epoch");
}
// verify that the transaction is really in the block
bytes memory payload = Merkle.prove(params[i].merkleProof, Block.txRootHash(params[i].blockHeader));
// get call data
(bytes32 requestId, bytes memory receivedData, address to, uint64 chainIdTo) = Block.decodeRequest(payload);
require(chainIdTo == block.chainid, "Bridge: wrong chain id");
require(requestIdChecker[requestId] == false, "Bridge: request id already seen");
requestIdChecker[requestId] = true;
uint256 length = receivedData.length - 1;
payload = new bytes(length);
for (uint j; j < length; ++j) {
payload[j] = receivedData[j];
}
if (receivedData[receivedData.length - 1] == 0x01){
require(payload.length == 128, "Bridge: Invalid message length");
(bytes32 payload_, bytes32 sender, uint256 chainIdFrom, ) = abi.decode(receivedData, (bytes32, bytes32, uint256, bytes32));
IReceiver(receiver).receiveHash(sender, uint64(chainIdFrom), payload_, requestId);
} else if (receivedData[receivedData.length - 1] == 0x00) {
(bytes memory payload_, bytes32 sender, uint256 chainIdFrom, ) = abi.decode(receivedData, (bytes, bytes32, uint256, bytes32));
IReceiver(receiver).receiveData(sender, uint64(chainIdFrom), payload_, requestId);
} else {
revert("Bridge: wrong message");
}
}
return true;
}
/**
* @dev Set new state.
*
* Controlled by operator. Can be used to emergency pause send or send and receive data.
*
* @param state_ Active\Inactive state
*/
function setState(State state_) external onlyRole(OPERATOR_ROLE) {
state = state_;
emit StateSet(state);
}
/**
* @dev Set new receiver.
*
* Controlled by operator.
*
* @param receiver_ Receiver address
*/
function setReceiver(address receiver_) external onlyRole(OPERATOR_ROLE) {
require(receiver_ != address(0), "BridgeV3: zero address");
receiver = receiver_;
emit ReceiverSet(receiver_);
}
/**
* @dev Set new price oracle.
*
* Controlled by operator.
*
* @param priceOracle_ GasPriceOracle address
*/
function setPriceOracle(address priceOracle_) external onlyRole(OPERATOR_ROLE) {
require(priceOracle_ != address(0), "BridgeV3: zero address");
priceOracle = priceOracle_;
emit PriceOracleSet(priceOracle_);
}
/**
* @dev Verifies epoch.
*
* @param epoch current or previous epoch;
* @param params oracle tx params
*/
function verifyEpoch(Bls.Epoch storage epoch, ReceiveParams calldata params) internal view {
Block.verify(
epoch,
params.blockHeader,
params.votersPubKey,
params.votersSignature,
params.votersMask
);
}
/**
* @dev Moves current epoch and current request filter to previous.
*/
function rotateEpoch() internal {
previousEpoch = currentEpoch;
Bls.Epoch memory epoch;
currentEpoch = epoch;
}
/**
* @dev Hook on start new epoch.
*/
function onEpochStart(uint64 protocolVersion_) internal virtual {
emit EpochUpdated(abi.encode(currentEpoch.publicKey), currentEpoch.epochNum, protocolVersion_);
}
}// SPDX-License-Identifier: UNLICENSED
// Copyright (c) Eywa.Fi, 2021-2025 - all rights reserved
pragma solidity ^0.8.20;
interface IBridge {
enum State {
Active, // data send and receive possible
Inactive, // data send and receive impossible
Limited // only data receive possible
}
struct SendParams {
/// @param requestId unique request ID
bytes32 requestId;
/// @param data call data
bytes data;
/// @param to receiver contract address
bytes32 to;
/// @param chainIdTo destination chain ID
uint64 chainIdTo;
}
function sendV3(
SendParams calldata params,
address sender,
uint256 nonce,
bytes memory options
) external payable;
function estimateGasFee(
SendParams memory params,
address sender,
bytes memory options
) external view returns (uint256);
}// SPDX-License-Identifier: UNLICENSED
// Copyright (c) Eywa.Fi, 2021-2025 - all rights reserved
pragma solidity ^0.8.20;
import "../interfaces/IBridge.sol";
interface IBridgeV3 is IBridge {
struct ReceiveParams {
/// @param blockHeader block header serialization
bytes blockHeader;
/// @param merkleProof OracleRequest transaction payload and its Merkle audit path
bytes merkleProof;
/// @param votersPubKey aggregated public key of the old epoch participants, who voted for the block
bytes votersPubKey;
/// @param votersSignature aggregated signature of the old epoch participants, who voted for the block
bytes votersSignature;
/// @param votersMask bitmask of epoch participants, who voted, among all participants
uint256 votersMask;
}
enum ChainType {
DEFAULT,
ARBITRUM,
OPTIMISM
}
function receiveV3(ReceiveParams[] calldata params) external returns (bool);
}// SPDX-License-Identifier: UNLICENSED
// Copyright (c) Eywa.Fi, 2021-2025 - all rights reserved
pragma solidity ^0.8.20;
interface IOracle {
function estimateFeeByChain(
uint64 chainIdTo,
uint256 callDataLength,
uint256 gasExecute
) external view returns (uint256 fee, uint256 priceRatio);
}// SPDX-License-Identifier: UNLICENSED
// Copyright (c) Eywa.Fi, 2021-2025 - all rights reserved
pragma solidity ^0.8.20;
interface IReceiver {
function receiveData(bytes32 sender, uint64 chainIdFrom, bytes memory receivedData, bytes32 requestId) external;
function receiveHash(bytes32 sender, uint64 chainIdFrom, bytes32 receivedHash, bytes32 requestId) external;
}// SPDX-License-Identifier: UNLICENSED
// Copyright (c) Eywa.Fi, 2021-2023 - all rights reserved
pragma solidity ^0.8.20;
import "../utils/Bls.sol";
import "../utils/Utils.sol";
import "../utils/ZeroCopySource.sol";
library Block {
function txRootHash(bytes calldata payload) internal pure returns (bytes32 txRootHash_) {
txRootHash_ = Utils.bytesToBytes32(payload[72:104]);
}
function epochHash(bytes calldata payload) internal pure returns (bytes32 epochHash_) {
epochHash_ = Utils.bytesToBytes32(payload[40:72]);
}
function decodeRequest(bytes memory payload) internal pure returns (
bytes32 requestId,
bytes memory data,
address to,
uint64 chainIdTo
) {
uint256 off = 0;
(requestId, off) = ZeroCopySource.NextHash(payload, off);
(chainIdTo, off) = ZeroCopySource.NextUint64(payload, off);
(to, off) = ZeroCopySource.NextAddress(payload, off);
(data, off) = ZeroCopySource.NextVarBytes(payload, off);
}
function decodeEpochUpdate(bytes memory payload) internal pure returns (
uint64 newEpochVersion,
uint32 newEpochNum,
bytes memory newKey,
uint8 newEpochParticipantsCount
) {
uint256 off = 0;
(newEpochVersion, off) = ZeroCopySource.NextUint64(payload, off);
(newEpochNum, off) = ZeroCopySource.NextUint32(payload, off);
(newEpochParticipantsCount, off) = ZeroCopySource.NextUint8(payload, off);
(newKey, off) = ZeroCopySource.NextVarBytes(payload, off);
}
function verify(
Bls.Epoch memory epoch,
bytes calldata blockHeader,
bytes calldata votersPubKey,
bytes calldata votersSignature,
uint256 votersMask
) internal view {
require(popcnt(votersMask) > (uint256(epoch.participantsCount) * 2) / 3, "Block: not enough participants");
require(epoch.participantsCount == 255 || votersMask < (1 << epoch.participantsCount), "Block: bitmask too big");
require(
Bls.verifyMultisig(epoch, votersPubKey, blockHeader, votersSignature, votersMask),
"Block: multisig mismatch"
);
}
function popcnt(uint256 mask) internal pure returns (uint256 cnt) {
cnt = 0;
while (mask != 0) {
mask = mask & (mask - 1);
cnt++;
}
}
}// SPDX-License-Identifier: UNLICENSED
// Copyright (c) ConsenSys
// Copyright (c) Eywa.Fi, 2021-2023 - all rights reserved
pragma solidity ^0.8.20;
import "./ModUtils.sol";
/**
* @title Verify BLS Threshold Signed values.
*
* Much of the code in this file is derived from here:
* https://github.com/ConsenSys/gpact/blob/main/common/common/src/main/solidity/BlsSignatureVerification.sol
* https://github.com/ConsenSys/gpact/blob/main/contracts/contracts/src/common/BlsSignatureVerification.sol
*/
library Bls {
using ModUtils for uint256;
struct E1Point {
uint256 x;
uint256 y;
}
/**
* @dev Note that the ordering of the elements in each array needs to be the reverse of what you would
* normally have, to match the ordering expected by the precompile.
*/
struct E2Point {
uint256[2] x;
uint256[2] y;
}
/**
* @dev P is a prime over which we form a basic field;
* taken from go-ethereum/crypto/bn256/cloudflare/constants.go.
*/
uint256 constant P = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
struct Epoch {
/// @param sum of all participant public keys
E2Point publicKey;
/// @param // sum of H(Pub, i) hashes of all participants indexes
E1Point precomputedSum;
/// @param // participants count contributed to the epochKey
uint8 participantsCount;
/// @param epoch number
uint32 epochNum;
/// @param epoch hash
bytes32 epochHash;
}
/**
* @dev Tests that epoch is set or zero.
*/
function isSet(Epoch memory epoch) internal pure returns (bool) {
return epoch.publicKey.x[0] != 0 || epoch.publicKey.x[1] != 0;
}
/**
* @dev Reset the epoch.
*/
function reset(Epoch storage epoch) internal {
epoch.publicKey.x[0] = 0;
epoch.publicKey.x[1] = 0;
epoch.precomputedSum.x = 0;
epoch.epochHash = 0;
epoch.participantsCount = 0;
}
/**
* @dev Update epoch and precompute epoch sum as if all participants signed.
*
* @param epoch_ current epoch to update;
* @param epochPublicKey sum of all participant public keys;
* @param epochParticipantsCount number of participants;
* @param epochNum number of participants;
* @param epochHash epoch hash.
*/
function update(
Epoch storage epoch_,
bytes memory epochPublicKey,
uint8 epochParticipantsCount,
uint32 epochNum,
bytes32 epochHash
) internal {
E2Point memory pub = decodeE2Point(epochPublicKey);
E1Point memory sum = E1Point(0, 0);
uint256 index = 0;
bytes memory buf = abi.encodePacked(pub.x, pub.y, index);
while (index < epochParticipantsCount) {
assembly {
mstore(add(buf, 160), index)
} // overwrite index field, same as buf[128] = index
sum = addCurveE1(sum, hashToCurveE1(buf));
index++;
}
epoch_.publicKey = pub;
epoch_.precomputedSum = sum;
epoch_.participantsCount = epochParticipantsCount;
epoch_.epochNum = epochNum;
epoch_.epochHash = epochHash;
}
/**
* @dev Checks if the BLS multisignature is valid in the current epoch.
*
* @param epoch_ current epoch;
* @param partPublicKey Sum of participated public keys;
* @param message Message that was signed;
* @param partSignature Signature over the message;
* @param signersBitmask Bitmask of participants in this signature;
* @return True if the message was correctly signed by the given participants.
*/
function verifyMultisig(
Epoch memory epoch_,
bytes memory partPublicKey,
bytes memory message,
bytes memory partSignature,
uint256 signersBitmask
) internal view returns (bool) {
E1Point memory sum = epoch_.precomputedSum;
uint256 index = 0;
uint256 mask = 1;
bytes memory buf = abi.encodePacked(epoch_.publicKey.x, epoch_.publicKey.y, index);
while (index < epoch_.participantsCount) {
if (signersBitmask & mask == 0) {
assembly {
mstore(add(buf, 160), index)
} // overwrite index field, same as buf[128] = index
sum = addCurveE1(sum, negate(hashToCurveE1(buf)));
}
mask <<= 1;
index++;
}
E1Point[] memory e1points = new E1Point[](3);
E2Point[] memory e2points = new E2Point[](3);
e1points[0] = negate(decodeE1Point(partSignature));
e1points[1] = hashToCurveE1(abi.encodePacked(epoch_.publicKey.x, epoch_.publicKey.y, message));
e1points[2] = sum;
e2points[0] = G2();
e2points[1] = decodeE2Point(partPublicKey);
e2points[2] = epoch_.publicKey;
return pairing(e1points, e2points);
}
/**
* @return The generator of E1.
*/
function G1() private pure returns (E1Point memory) {
return E1Point(1, 2);
}
/**
* @return The generator of E2.
*/
function G2() private pure returns (E2Point memory) {
return E2Point({
x: [
11559732032986387107991004021392285783925812861821192530917403151452391805634,
10857046999023057135944570762232829481370756359578518086990519993285655852781
],
y: [
4082367875863433681332203403145435568316851327593401208105741076214120093531,
8495653923123431417604973247489272438418190587263600148770280649306958101930
]
});
}
/**
* Negate a point: Assuming the point isn't at infinity, the negation is same x value with -y.
*
* @dev Negates a point in E1;
* @param _point Point to negate;
* @return The negated point.
*/
function negate(E1Point memory _point) private pure returns (E1Point memory) {
if (isAtInfinity(_point)) {
return E1Point(0, 0);
}
return E1Point(_point.x, P - (_point.y % P));
}
/**
* Computes the pairing check e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
*
* @param _e1points List of points in E1;
* @param _e2points List of points in E2;
* @return True if pairing check succeeds.
*/
function pairing(E1Point[] memory _e1points, E2Point[] memory _e2points) private view returns (bool) {
require(_e1points.length == _e2points.length, "Bls: point count mismatch");
uint256 elements = _e1points.length;
uint256 inputSize = elements * 6;
uint256[] memory input = new uint256[](inputSize);
for (uint256 i = 0; i < elements; i++) {
input[i * 6 + 0] = _e1points[i].x;
input[i * 6 + 1] = _e1points[i].y;
input[i * 6 + 2] = _e2points[i].x[0];
input[i * 6 + 3] = _e2points[i].x[1];
input[i * 6 + 4] = _e2points[i].y[0];
input[i * 6 + 5] = _e2points[i].y[1];
}
uint256[1] memory out;
bool success;
assembly {
// Start at memory offset 0x20 rather than 0 as input is a variable length array.
// Location 0 is the length field.
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
}
// The pairing operation will fail if the input data isn't the correct size (this won't happen
// given the code above), or if one of the points isn't on the curve.
require(success, "Bls: pairing operation failed");
return out[0] != 0;
}
/**
* @dev Checks if the point is the point at infinity.
*
* @param _point a point on E1;
* @return true if the point is the point at infinity.
*/
function isAtInfinity(E1Point memory _point) private pure returns (bool) {
return (_point.x == 0 && _point.y == 0);
}
/**
* @dev Hash a byte array message, m, and map it deterministically to a point on G1.
* Note that this approach was chosen for its simplicity /
* lower gas cost on the EVM, rather than good distribution of points on G1.
*/
function hashToCurveE1(bytes memory m) internal view returns (E1Point memory) {
bytes32 h = sha256(m);
uint256 x = uint256(h) % P;
uint256 y;
while (true) {
y = YFromX(x);
if (y > 0) {
return E1Point(x, y);
}
x += 1;
}
revert("hashToCurveE1: unreachable end point");
}
/**
* @dev g1YFromX computes a Y value for a G1 point based on an X value.
* This computation is simply evaluating the curve equation for Y on a given X,
* and allows a point on the curve to be represented by just an X value + a sign bit.
*/
function YFromX(uint256 x) internal view returns (uint256) {
return ((x.modExp(3, P) + 3) % P).modSqrt(P);
}
/**
* @dev return the sum of two points of G1.
*/
function addCurveE1(E1Point memory _p1, E1Point memory _p2) internal view returns (E1Point memory res) {
uint256[4] memory input;
input[0] = _p1.x;
input[1] = _p1.y;
input[2] = _p2.x;
input[3] = _p2.y;
bool success;
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0x80, res, 0x40)
}
require(success, "Bls: add points failed");
}
function decodeE1Point(bytes memory _sig) internal pure returns (E1Point memory signature) {
uint256 sigx;
uint256 sigy;
assembly {
sigx := mload(add(_sig, 0x20))
sigy := mload(add(_sig, 0x40))
}
signature.x = sigx;
signature.y = sigy;
}
function decodeE2Point(bytes memory _pubKey) internal pure returns (E2Point memory pubKey) {
uint256 x1;
uint256 x2;
uint256 y1;
uint256 y2;
assembly {
x1 := mload(add(_pubKey, 0x20))
x2 := mload(add(_pubKey, 0x40))
y1 := mload(add(_pubKey, 0x60))
y2 := mload(add(_pubKey, 0x80))
}
pubKey.x[0] = x1;
pubKey.x[1] = x2;
pubKey.y[0] = y1;
pubKey.y[1] = y2;
}
}// SPDX-License-Identifier: UNLICENSED
// Copyright (c) Eywa.Fi, 2021-2023 - all rights reserved
pragma solidity ^0.8.20;
import "./ZeroCopySource.sol";
library Merkle {
/** @notice Do hash leaf as the multi-chain does.
*
* @param data_ Data in bytes format;
* @return result Hashed value in bytes32 format.
*/
function hashLeaf(bytes memory data_) internal pure returns (bytes32 result) {
result = sha256(abi.encodePacked(uint8(0x0), data_));
}
/** @notice Do hash children as the multi-chain does.
*
* @param l_ Left node;
* @param r_ Right node;
* @return result Hashed value in bytes32 format.
*/
function hashChildren(bytes32 l_, bytes32 r_) internal pure returns (bytes32 result) {
result = sha256(abi.encodePacked(bytes1(0x01), l_, r_));
}
/** @notice Verify merkle proove.
*
* @param auditPath_ Merkle path;
* @param root_ Merkle tree root;
* @return The verified value included in auditPath_.
*/
function prove(bytes memory auditPath_, bytes32 root_) internal pure returns (bytes memory) {
uint256 off = 0;
bytes memory value;
(value, off) = ZeroCopySource.NextVarBytes(auditPath_, off);
bytes32 hash = hashLeaf(value);
uint256 size = (auditPath_.length - off) / 33; // 33 = sizeof(uint256) + 1
bytes32 nodeHash;
uint8 pos;
for (uint256 i = 0; i < size; i++) {
(pos, off) = ZeroCopySource.NextUint8(auditPath_, off);
(nodeHash, off) = ZeroCopySource.NextHash(auditPath_, off);
if (pos == 0x00) {
hash = hashChildren(nodeHash, hash);
} else if (pos == 0x01) {
hash = hashChildren(hash, nodeHash);
} else {
revert("Merkle: prove eod");
}
}
require(hash == root_, "Merkle: prove root");
return value;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
library ModUtils {
/**
* @dev Wrap the modular exponent pre-compile introduced in Byzantium.
* Returns base^exponent mod p.
*/
function modExp(
uint256 base,
uint256 exponent,
uint256 p
) internal view returns (uint256 o) {
/* solium-disable-next-line */
assembly {
// Args for the precompile: [<length_of_BASE> <length_of_EXPONENT>
// <length_of_MODULUS> <BASE> <EXPONENT> <MODULUS>]
let output := mload(0x40)
let args := add(output, 0x20)
mstore(args, 0x20)
mstore(add(args, 0x20), 0x20)
mstore(add(args, 0x40), 0x20)
mstore(add(args, 0x60), base)
mstore(add(args, 0x80), exponent)
mstore(add(args, 0xa0), p)
// 0x05 is the modular exponent contract address
if iszero(staticcall(not(0), 0x05, args, 0xc0, output, 0x20)) {
revert(0, 0)
}
o := mload(output)
}
}
/**
* @dev Calculates and returns the square root of a mod p if such a square
* root exists. The modulus p must be an odd prime. If a square root does
* not exist, function returns 0.
*/
function modSqrt(uint256 a, uint256 p) internal view returns (uint256) {
if (legendre(a, p) != 1) {
return 0;
}
if (a == 0) {
return 0;
}
if (p % 4 == 3) {
return modExp(a, (p + 1) / 4, p);
}
uint256 s = p - 1;
uint256 e = 0;
while (s % 2 == 0) {
s = s / 2;
e = e + 1;
}
// Note the smaller int- finding n with Legendre symbol or -1
// should be quick
uint256 n = 2;
while (legendre(n, p) != -1) {
n = n + 1;
}
uint256 x = modExp(a, (s + 1) / 2, p);
uint256 b = modExp(a, s, p);
uint256 g = modExp(n, s, p);
uint256 r = e;
uint256 gs = 0;
uint256 m = 0;
uint256 t = b;
while (true) {
t = b;
m = 0;
for (m = 0; m < r; m++) {
if (t == 1) {
break;
}
t = modExp(t, 2, p);
}
if (m == 0) {
return x;
}
gs = modExp(g, uint256(2)**(r - m - 1), p);
g = (gs * gs) % p;
x = (x * gs) % p;
b = (b * g) % p;
r = m;
}
revert("modSqrt: unreachable end point");
}
/**
* @dev Calculates the Legendre symbol of the given a mod p.
* @return Returns 1 if a is a quadratic residue mod p, -1 if it is
* a non-quadratic residue, and 0 if a is 0.
*/
function legendre(uint256 a, uint256 p) internal view returns (int256) {
uint256 raised = modExp(a, (p - 1) / uint256(2), p);
if (raised == 0 || raised == 1) {
return int256(raised);
} else if (raised == p - 1) {
return -1;
}
revert("Failed to calculate legendre.");
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "solidity-bytes-utils/contracts/BytesLib.sol";
library Utils {
/* @notice Convert the bytes array to bytes32 type, the bytes array length must be 32
* @param _bs Source bytes array
* @return bytes32
*/
function bytesToBytes32(bytes memory _bs) internal pure returns (bytes32 value) {
require(_bs.length == 32, "bytes length is not 32.");
assembly {
// load 32 bytes from memory starting from position _bs + 0x20 since the first 0x20 bytes stores _bs length
value := mload(add(_bs, 0x20))
}
}
/* @notice Convert bytes to uint256
* @param _b Source bytes should have length of 32
* @return uint256
*/
function bytesToUint256(bytes memory _bs) internal pure returns (uint256 value) {
require(_bs.length == 32, "bytes length is not 32.");
assembly {
// load 32 bytes from memory starting from position _bs + 32
value := mload(add(_bs, 0x20))
}
require(value <= 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, "Value exceeds the range");
}
/* @notice Convert uint256 to bytes
* @param _b uint256 that needs to be converted
* @return bytes
*/
function uint256ToBytes(uint256 _value) internal pure returns (bytes memory bs) {
require(
_value <= 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff,
"Value exceeds the range"
);
assembly {
// Get a location of some free memory and store it in result as
// Solidity does for memory variables.
bs := mload(0x40)
// Put 0x20 at the first word, the length of bytes for uint256 value
mstore(bs, 0x20)
//In the next word, put value in bytes format to the next 32 bytes
mstore(add(bs, 0x20), _value)
// Update the free-memory pointer by padding our last write location to 32 bytes
mstore(0x40, add(bs, 0x40))
}
}
/* @notice Convert bytes to address
* @param _bs Source bytes: bytes length must be 20
* @return Converted address from source bytes
*/
function bytesToAddress(bytes memory _bs) internal pure returns (address addr) {
require(_bs.length == 20, "bytes length does not match address");
assembly {
// for _bs, first word store _bs.length, second word store _bs.value
// load 32 bytes from mem[_bs+20], convert it into Uint160, meaning we take last 20 bytes as addr (address).
addr := mload(add(_bs, 0x14))
}
}
/* @notice Convert address to bytes
* @param _addr Address need to be converted
* @return Converted bytes from address
*/
function addressToBytes(address _addr) internal pure returns (bytes memory bs) {
assembly {
// Get a location of some free memory and store it in result as
// Solidity does for memory variables.
bs := mload(0x40)
// Put 20 (address byte length) at the first word, the length of bytes for uint256 value
mstore(bs, 0x14)
// logical shift left _a by 12 bytes, change _a from right-aligned to left-aligned
mstore(add(bs, 0x20), shl(96, _addr))
// Update the free-memory pointer by padding our last write location to 32 bytes
mstore(0x40, add(bs, 0x40))
}
}
/* @notice Compare if two bytes are equal, which are in storage and memory, seperately
Refer from https://github.com/summa-tx/bitcoin-spv/blob/master/solidity/contracts/BytesLib.sol#L368
* @param _preBytes The bytes stored in storage
* @param _postBytes The bytes stored in memory
* @return Bool type indicating if they are equal
*/
function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) {
bool success = true;
assembly {
// we know _preBytes_offset is 0
let fslot := sload(_preBytes.slot)
// Arrays of 31 bytes or less have an even value in their slot,
// while longer arrays have an odd value. The actual length is
// the slot divided by two for odd values, and the lowest order
// byte divided by two for even values.
// If the slot is even, bitwise and the slot with 255 and divide by
// two to get the length. If the slot is odd, bitwise and the slot
// with -1 and divide by two.
let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
let mlength := mload(_postBytes)
// if lengths don't match the arrays are not equal
switch eq(slength, mlength)
case 1 {
// fslot can contain both the length and contents of the array
// if slength < 32 bytes so let's prepare for that
// v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
// slength != 0
if iszero(iszero(slength)) {
switch lt(slength, 32)
case 1 {
// blank the last byte which is the length
fslot := mul(div(fslot, 0x100), 0x100)
if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
// unsuccess:
success := 0
}
}
default {
// cb is a circuit breaker in the for loop since there's
// no said feature for inline assembly loops
// cb = 1 - don't breaker
// cb = 0 - break
let cb := 1
// get the keccak hash to get the contents of the array
mstore(0x0, _preBytes.slot)
let sc := keccak256(0x0, 0x20)
let mc := add(_postBytes, 0x20)
let end := add(mc, mlength)
// the next line is the loop condition:
// while(uint(mc < end) + cb == 2)
for {
} eq(add(lt(mc, end), cb), 2) {
sc := add(sc, 1)
mc := add(mc, 0x20)
} {
if iszero(eq(sload(sc), mload(mc))) {
// unsuccess:
success := 0
cb := 0
}
}
}
}
}
default {
// unsuccess:
success := 0
}
}
return success;
}
/* @notice Slice the _bytes from _start index till the result has length of _length
Refer from https://github.com/summa-tx/bitcoin-spv/blob/master/solidity/contracts/BytesLib.sol#L246
* @param _bytes The original bytes needs to be sliced
* @param _start The index of _bytes for the start of sliced bytes
* @param _length The index of _bytes for the end of sliced bytes
* @return The sliced bytes
*/
function slice(
bytes memory _bytes,
uint256 _start,
uint256 _length
) internal pure returns (bytes memory) {
require(_bytes.length >= (_start + _length));
bytes memory tempBytes;
assembly {
switch iszero(_length)
case 0 {
// Get a location of some free memory and store it in tempBytes as
// Solidity does for memory variables.
tempBytes := mload(0x40)
// The first word of the slice result is potentially a partial
// word read from the original array. To read it, we calculate
// the length of that partial word and start copying that many
// bytes into the array. The first word we copy will start with
// data we don't care about, but the last `lengthmod` bytes will
// land at the beginning of the contents of the new array. When
// we're done copying, we overwrite the full first word with
// the actual length of the slice.
// lengthmod <= _length % 32
let lengthmod := and(_length, 31)
// The multiplication in the next line is necessary
// because when slicing multiples of 32 bytes (lengthmod == 0)
// the following copy loop was copying the origin's length
// and then ending prematurely not copying everything it should.
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
let end := add(mc, _length)
for {
// The multiplication in the next line has the same exact purpose
// as the one above.
let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
} lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} {
mstore(mc, mload(cc))
}
mstore(tempBytes, _length)
//update free-memory pointer
//allocating the array padded to 32 bytes like the compiler does now
mstore(0x40, and(add(mc, 31), not(31)))
}
//if we want a zero-length slice let's just return a zero-length array
default {
tempBytes := mload(0x40)
mstore(0x40, add(tempBytes, 0x20))
}
}
return tempBytes;
}
/* @notice Check if the elements number of _signers within _keepers array is no less than _m
* @param _keepers The array consists of serveral address
* @param _signers Some specific addresses to be looked into
* @param _m The number requirement paramter
* @return True means containment, false meansdo do not contain.
*/
function containMAddresses(
address[] memory _keepers,
address[] memory _signers,
uint256 _m
) internal pure returns (bool) {
uint256 m = 0;
for (uint256 i = 0; i < _signers.length; i++) {
for (uint256 j = 0; j < _keepers.length; j++) {
if (_signers[i] == _keepers[j]) {
m++;
delete _keepers[j];
}
}
}
return m >= _m;
}
/* @notice TODO
* @param key
* @return
*/
function compressMCPubKey(bytes memory key) internal pure returns (bytes memory newkey) {
require(key.length >= 67, "key lenggh is too short");
newkey = slice(key, 0, 35);
if (uint8(key[66]) % 2 == 0) {
newkey[2] = 0x02;
} else {
newkey[2] = 0x03;
}
return newkey;
}
/**
* @dev Returns true if `account` is a contract.
* Refer from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol#L18
*
* This test is non-exhaustive, and there may be false-negatives: during the
* execution of a contract's constructor, its address will be reported as
* not containing 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.
*/
function isContract(address account) internal view returns (bool) {
// This method relies in extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
// According to EIP-1052, 0x0 is the value returned for not-yet created accounts
// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
// for accounts without code, i.e. `keccak256('')`
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
// solhint-disable-next-line no-inline-assembly
assembly {
codehash := extcodehash(account)
}
return (codehash != 0x0 && codehash != accountHash);
}
/**
* @dev Extracts error from the returned data of inter-contract call
*/
function extractErrorMessage(bytes memory data) internal pure returns (string memory) {
if (data.length < 68) return "unknown error";
bytes memory revertData = BytesLib.slice(data, 4, data.length - 4);
return abi.decode(revertData, (string));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @dev Wrappers over decoding and deserialization operation from bytes into bassic types in Solidity for PolyNetwork cross chain utility.
*
* Decode into basic types in Solidity from bytes easily. It's designed to be used
* for PolyNetwork cross chain application, and the decoding rules on Ethereum chain
* and the encoding rule on other chains should be consistent, and . Here we
* follow the underlying deserialization rule with implementation found here:
* https://github.com/polynetwork/poly/blob/master/common/zero_copy_source.go
*
* Using this library instead of the unchecked serialization method can help reduce
* the risk of serious bugs and handfule, so it's recommended to use it.
*
* Please note that risk can be minimized, yet not eliminated.
*/
library ZeroCopySource {
/* @notice Read next byte as boolean type starting at offset from buff
* @param buff Source bytes array
* @param offset The position from where we read the boolean value
* @return The the read boolean value and new offset
*/
function NextBool(bytes memory buff, uint256 offset) internal pure returns (bool, uint256) {
require(offset + 1 <= buff.length, "Offset exceeds limit");
// byte === bytes1
bytes1 v;
assembly {
v := mload(add(add(buff, 0x20), offset))
}
bool value;
if (v == 0x01) {
value = true;
} else if (v == 0x00) {
value = false;
} else {
revert("NextBool value error");
}
return (value, offset + 1);
}
/* @notice Read next byte as uint8 starting at offset from buff
* @param buff Source bytes array
* @param offset The position from where we read the byte value
* @return The read uint8 value and new offset
*/
function NextUint8(bytes memory buff, uint256 offset) internal pure returns (uint8, uint256) {
require(offset + 1 <= buff.length && offset < offset + 1, "NextUint8, Offset exceeds maximum");
uint8 v;
assembly {
let tmpbytes := mload(0x40)
let bvalue := mload(add(add(buff, 0x20), offset))
mstore8(tmpbytes, byte(0, bvalue))
mstore(0x40, add(tmpbytes, 0x01))
v := mload(sub(tmpbytes, 0x1f))
}
return (v, offset + 1);
}
/* @notice Read next two bytes as uint16 type starting from offset
* @param buff Source bytes array
* @param offset The position from where we read the uint16 value
* @return The read uint16 value and updated offset
*/
function NextUint16(bytes memory buff, uint256 offset) internal pure returns (uint16, uint256) {
require(offset + 2 <= buff.length && offset < offset + 2, "NextUint16, offset exceeds maximum");
uint16 v;
assembly {
let tmpbytes := mload(0x40)
let bvalue := mload(add(add(buff, 0x20), offset))
mstore8(tmpbytes, byte(0x01, bvalue))
mstore8(add(tmpbytes, 0x01), byte(0, bvalue))
mstore(0x40, add(tmpbytes, 0x02))
v := mload(sub(tmpbytes, 0x1e))
}
return (v, offset + 2);
}
/* @notice Read next four bytes as uint32 type starting from offset
* @param buff Source bytes array
* @param offset The position from where we read the uint32 value
* @return The read uint32 value and updated offset
*/
function NextUint32(bytes memory buff, uint256 offset) internal pure returns (uint32, uint256) {
require(offset + 4 <= buff.length && offset < offset + 4, "NextUint32, offset exceeds maximum");
uint32 v;
assembly {
let tmpbytes := mload(0x40)
let byteLen := 0x04
for {
let tindex := 0x00
let bindex := sub(byteLen, 0x01)
let bvalue := mload(add(add(buff, 0x20), offset))
} lt(tindex, byteLen) {
tindex := add(tindex, 0x01)
bindex := sub(bindex, 0x01)
} {
mstore8(add(tmpbytes, tindex), byte(bindex, bvalue))
}
mstore(0x40, add(tmpbytes, byteLen))
v := mload(sub(tmpbytes, sub(0x20, byteLen)))
}
return (v, offset + 4);
}
/* @notice Read next eight bytes as uint64 type starting from offset
* @param buff Source bytes array
* @param offset The position from where we read the uint64 value
* @return The read uint64 value and updated offset
*/
function NextUint64(bytes memory buff, uint256 offset) internal pure returns (uint64, uint256) {
require(offset + 8 <= buff.length && offset < offset + 8, "NextUint64, offset exceeds maximum");
uint64 v;
assembly {
let tmpbytes := mload(0x40)
let byteLen := 0x08
for {
let tindex := 0x00
let bindex := sub(byteLen, 0x01)
let bvalue := mload(add(add(buff, 0x20), offset))
} lt(tindex, byteLen) {
tindex := add(tindex, 0x01)
bindex := sub(bindex, 0x01)
} {
mstore8(add(tmpbytes, tindex), byte(bindex, bvalue))
}
mstore(0x40, add(tmpbytes, byteLen))
v := mload(sub(tmpbytes, sub(0x20, byteLen)))
}
return (v, offset + 8);
}
/* @notice Read next 32 bytes as uint256 type starting from offset,
there are limits considering the numerical limits in multi-chain
* @param buff Source bytes array
* @param offset The position from where we read the uint256 value
* @return The read uint256 value and updated offset
*/
function NextUint255(bytes memory buff, uint256 offset) internal pure returns (uint256, uint256) {
require(offset + 32 <= buff.length && offset < offset + 32, "NextUint255, offset exceeds maximum");
uint256 v;
assembly {
let tmpbytes := mload(0x40)
let byteLen := 0x20
for {
let tindex := 0x00
let bindex := sub(byteLen, 0x01)
let bvalue := mload(add(add(buff, 0x20), offset))
} lt(tindex, byteLen) {
tindex := add(tindex, 0x01)
bindex := sub(bindex, 0x01)
} {
mstore8(add(tmpbytes, tindex), byte(bindex, bvalue))
}
mstore(0x40, add(tmpbytes, byteLen))
v := mload(tmpbytes)
}
require(v <= 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, "Value exceeds the range");
return (v, offset + 32);
}
/* @notice Read next variable bytes starting from offset,
the decoding rule coming from multi-chain
* @param buff Source bytes array
* @param offset The position from where we read the bytes value
* @return The read variable bytes array value and updated offset
*/
function NextVarBytes(bytes memory buff, uint256 offset) internal pure returns (bytes memory, uint256) {
uint256 len;
(len, offset) = NextVarUint(buff, offset);
require(offset + len <= buff.length && offset < offset + len, "NextVarBytes, offset exceeds maximum");
bytes memory tempBytes;
assembly {
switch iszero(len)
case 0 {
// Get a location of some free memory and store it in tempBytes as
// Solidity does for memory variables.
tempBytes := mload(0x40)
// The first word of the slice result is potentially a partial
// word read from the original array. To read it, we calculate
// the length of that partial word and start copying that many
// bytes into the array. The first word we copy will start with
// data we don't care about, but the last `lengthmod` bytes will
// land at the beginning of the contents of the new array. When
// we're done copying, we overwrite the full first word with
// the actual length of the slice.
let lengthmod := and(len, 31)
// The multiplication in the next line is necessary
// because when slicing multiples of 32 bytes (lengthmod == 0)
// the following copy loop was copying the origin's length
// and then ending prematurely not copying everything it should.
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
let end := add(mc, len)
for {
// The multiplication in the next line has the same exact purpose
// as the one above.
let cc := add(add(add(buff, lengthmod), mul(0x20, iszero(lengthmod))), offset)
} lt(mc, end) {
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} {
mstore(mc, mload(cc))
}
mstore(tempBytes, len)
//update free-memory pointer
//allocating the array padded to 32 bytes like the compiler does now
mstore(0x40, and(add(mc, 31), not(31)))
}
//if we want a zero-length slice let's just return a zero-length array
default {
tempBytes := mload(0x40)
mstore(tempBytes, 0)
mstore(0x40, add(tempBytes, 0x20))
}
}
return (tempBytes, offset + len);
}
/* @notice Read next 32 bytes starting from offset,
* @param buff Source bytes array
* @param offset The position from where we read the bytes value
* @return The read bytes32 value and updated offset
*/
function NextHash(bytes memory buff, uint256 offset) internal pure returns (bytes32, uint256) {
require(offset + 32 <= buff.length && offset < offset + 32, "NextHash, offset exceeds maximum");
bytes32 v;
assembly {
v := mload(add(buff, add(offset, 0x20)))
}
return (v, offset + 32);
}
/* @notice Read next 20 bytes starting from offset,
* @param buff Source bytes array
* @param offset The position from where we read the bytes value
* @return The read bytes20 value and updated offset
*/
function NextAddress(bytes memory buff, uint256 offset) internal pure returns (address, uint256) {
require(offset + 20 <= buff.length && offset < offset + 20, "NextAddress, offset exceeds maximum");
bytes20 v;
assembly {
v := mload(add(buff, add(offset, 0x20)))
}
return (address(v), offset + 20);
}
function NextVarUint(bytes memory buff, uint256 offset) internal pure returns (uint256, uint256) {
uint8 v;
(v, offset) = NextUint8(buff, offset);
uint256 value;
if (v == 0xFD) {
// return NextUint16(buff, offset);
(value, offset) = NextUint16(buff, offset);
require(value >= 0xFD && value <= 0xFFFF, "NextUint16, value outside range");
return (value, offset);
} else if (v == 0xFE) {
// return NextUint32(buff, offset);
(value, offset) = NextUint32(buff, offset);
require(value > 0xFFFF && value <= 0xFFFFFFFF, "NextVarUint, value outside range");
return (value, offset);
} else if (v == 0xFF) {
// return NextUint64(buff, offset);
(value, offset) = NextUint64(buff, offset);
require(value > 0xFFFFFFFF, "NextVarUint, value outside range");
return (value, offset);
} else {
// return (uint8(v), offset);
value = uint8(v);
require(value < 0xFD, "NextVarUint, value outside range");
return (value, offset);
}
}
}{
"evmVersion": "shanghai",
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"remappings": [
"project/:@openzeppelin/contracts/=npm/@openzeppelin/[email protected]/",
"project/:@openzeppelin/contracts/=npm/@openzeppelin/[email protected]/",
"project/:@openzeppelin/contracts/=npm/@openzeppelin/[email protected]/",
"project/:solidity-bytes-utils/=npm/[email protected]/"
]
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"string","name":"tag_","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"epochMinDuration","type":"uint256"}],"name":"EpochMinDurationSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"epochMinRequestUpdateDuration","type":"uint256"}],"name":"EpochMinRequestUpdateDurationSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"currentEpochNum","type":"uint32"},{"indexed":false,"internalType":"uint64","name":"protocolVersion","type":"uint64"}],"name":"EpochUpdateRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"key","type":"bytes"},{"indexed":false,"internalType":"uint32","name":"epochNum","type":"uint32"},{"indexed":false,"internalType":"uint64","name":"protocolVersion","type":"uint64"}],"name":"EpochUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"requestId","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"gasAmount","type":"uint32"}],"name":"GasPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"nodeRegistry","type":"address"}],"name":"NodeRegistrySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"priceOracle","type":"address"}],"name":"PriceOracleSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"nextVersion","type":"uint64"}],"name":"ProtocolVersionUpdateRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"receiver","type":"address"}],"name":"ReceiverSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"requestId","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint64","name":"chainIdTo","type":"uint64"}],"name":"RequestSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum IBridge.State","name":"state","type":"uint8"}],"name":"StateSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ValueWithdrawn","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GATEKEEPER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OPERATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VALIDATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"epochMinDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"epochMinRequestUpdateDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"epochStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"uint64","name":"chainIdTo","type":"uint64"}],"internalType":"struct IBridge.SendParams","name":"params","type":"tuple"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"options","type":"bytes"}],"name":"estimateGasFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentEpoch","outputs":[{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"uint8","name":"","type":"uint8"},{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPreviousEpoch","outputs":[{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"uint8","name":"","type":"uint8"},{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastRequestEpochUpdateTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextProtocolVersion","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nodeRegistry","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolVersion","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"blockHeader","type":"bytes"},{"internalType":"bytes","name":"merkleProof","type":"bytes"},{"internalType":"bytes","name":"votersPubKey","type":"bytes"},{"internalType":"bytes","name":"votersSignature","type":"bytes"},{"internalType":"uint256","name":"votersMask","type":"uint256"}],"internalType":"struct IBridgeV3.ReceiveParams[]","name":"params","type":"tuple[]"}],"name":"receiveV3","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"receiver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requestEpochUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"requestIdChecker","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"version","type":"uint64"}],"name":"requestProtocolVersionUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resetEpoch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"uint64","name":"chainIdTo","type":"uint64"}],"internalType":"struct IBridge.SendParams","name":"params","type":"tuple"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"options","type":"bytes"}],"name":"sendV3","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"epochMinDuration_","type":"uint256"}],"name":"setEpochMinDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"epochMinRequestUpdateDuration_","type":"uint256"}],"name":"setEpochMinRequestUpdateDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nodeRegistry_","type":"address"}],"name":"setNodeRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"priceOracle_","type":"address"}],"name":"setPriceOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver_","type":"address"}],"name":"setReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum IBridge.State","name":"state_","type":"uint8"}],"name":"setState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"state","outputs":[{"internalType":"enum IBridge.State","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tag","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"blockHeader","type":"bytes"},{"internalType":"bytes","name":"merkleProof","type":"bytes"},{"internalType":"bytes","name":"votersPubKey","type":"bytes"},{"internalType":"bytes","name":"votersSignature","type":"bytes"},{"internalType":"uint256","name":"votersMask","type":"uint256"}],"internalType":"struct IBridgeV3.ReceiveParams","name":"params","type":"tuple"}],"name":"updateEpoch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"value_","type":"uint256"}],"name":"withdrawValue","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234801562000010575f80fd5b50604051620050e4380380620050e4833981016040819052620000339162000206565b600160025580620000455f33620000bb565b60408051808201909152600580825264322e322e3360d81b6020830152906200006f90826200035f565b506007805460ff1916600117905560066200008b82826200035f565b5050601980546001600160801b0319166801000000000000000117905550611c20601b55610708601d5562000427565b620000c78282620000e5565b5f828152600160205260409020620000e0908262000184565b505050565b5f828152602081815260408083206001600160a01b038516845290915290205460ff1662000180575f828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556200013f3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b5f6200019a836001600160a01b038416620001a3565b90505b92915050565b5f818152600183016020526040812054620001ea57508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556200019d565b505f6200019d565b634e487b7160e01b5f52604160045260245ffd5b5f602080838503121562000218575f80fd5b82516001600160401b03808211156200022f575f80fd5b818501915085601f83011262000243575f80fd5b815181811115620002585762000258620001f2565b604051601f8201601f19908116603f01168101908382118183101715620002835762000283620001f2565b8160405282815288868487010111156200029b575f80fd5b5f93505b82841015620002be57848401860151818501870152928501926200029f565b5f86848301015280965050505050505092915050565b600181811c90821680620002e957607f821691505b6020821081036200030857634e487b7160e01b5f52602260045260245ffd5b50919050565b601f821115620000e0575f81815260208120601f850160051c81016020861015620003365750805b601f850160051c820191505b81811015620003575782815560010162000342565b505050505050565b81516001600160401b038111156200037b576200037b620001f2565b62000393816200038c8454620002d4565b846200030e565b602080601f831160018114620003c9575f8415620003b15750858301515b5f19600386901b1c1916600185901b17855562000357565b5f85815260208120601f198616915b82811015620003f957888601518255948401946001909101908401620003d8565b50858210156200041757878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b614caf80620004355f395ff3fe60806040526004361061023e575f3560e01c8063718da7ee11610134578063c49baebe116100b3578063d79de39e11610078578063d79de39e146106cc578063d9b5c4a5146106eb578063e1164b721461070a578063f5b541a614610729578063f60ca64114610749578063f7260d3e1461075e575f80fd5b8063c49baebe14610615578063ca15c87314610648578063d174ff8214610667578063d547741f1461067a578063d6fd317514610699575f80fd5b806391d14854116100f957806391d14854146105945780639a80fc66146105b3578063a217fddf146105c8578063b97dd9e2146105db578063c19d93fb146105ef575f80fd5b8063718da7ee146104ea57806379e99757146105095780638210a5bc146105285780639010d07c1461055657806391cdd9f014610575575f80fd5b80632ff1a529116101c0578063530e784f11610185578063530e784f1461045a57806354fd4d501461047957806356de96db1461048d5780635f1a6f05146104ac5780636e9cb097146104cb575f80fd5b80632ff1a529146103d357806331eab48a146103f257806336568abe14610406578063486a54f31461042557806351f9106614610439575f80fd5b806326339a211161020657806326339a21146103215780632ae9c600146103365780632ea940061461036d5780632f1874401461038e5780632f2ff15d146103b4575f80fd5b806301ffc9a714610242578063056768bf146102765780631bc2359a14610299578063248a9ca3146102bc5780632630c12f146102ea575b5f80fd5b34801561024d575f80fd5b5061026161025c366004614145565b61077d565b60405190151581526020015b60405180910390f35b348015610281575f80fd5b5061028a6107a7565b60405161026d939291906141b9565b3480156102a4575f80fd5b506102ae601b5481565b60405190815260200161026d565b3480156102c7575f80fd5b506102ae6102d63660046141ea565b5f9081526020819052604090206001015490565b3480156102f5575f80fd5b50600454610309906001600160a01b031681565b6040516001600160a01b03909116815260200161026d565b34801561032c575f80fd5b506102ae601c5481565b348015610341575f80fd5b50601954610355906001600160401b031681565b6040516001600160401b03909116815260200161026d565b348015610378575f80fd5b5061038c6103873660046141ea565b6107ec565b005b348015610399575f80fd5b5060195461035590600160401b90046001600160401b031681565b3480156103bf575f80fd5b5061038c6103ce366004614217565b610833565b3480156103de575f80fd5b5061038c6103ed366004614241565b61085c565b3480156103fd575f80fd5b5061038c610926565b348015610411575f80fd5b5061038c610420366004614217565b610aa1565b348015610430575f80fd5b5061038c610b1f565b348015610444575f80fd5b5061044d610c51565b60405161026d9190614267565b348015610465575f80fd5b5061038c610474366004614279565b610cdd565b348015610484575f80fd5b5061044d610d91565b348015610498575f80fd5b5061038c6104a7366004614292565b610d9e565b3480156104b7575f80fd5b5061038c6104c63660046141ea565b610e10565b3480156104d6575f80fd5b506102ae6104e5366004614382565b610e4f565b3480156104f5575f80fd5b5061038c610504366004614279565b610f1a565b348015610514575f80fd5b506102616105233660046143f0565b610fce565b348015610533575f80fd5b506102616105423660046141ea565b60086020525f908152604090205460ff1681565b348015610561575f80fd5b5061030961057036600461445e565b611765565b348015610580575f80fd5b5061038c61058f3660046141ea565b611783565b34801561059f575f80fd5b506102616105ae366004614217565b611860565b3480156105be575f80fd5b506102ae601d5481565b3480156105d3575f80fd5b506102ae5f81565b3480156105e6575f80fd5b5061028a611888565b3480156105fa575f80fd5b506007546106089060ff1681565b60405161026d9190614492565b348015610620575f80fd5b506102ae7f21702c8af46127c7fa207f89d0b0a8441bb32959a0ac7df790e9ab1a25c9892681565b348015610653575f80fd5b506102ae6106623660046141ea565b6118cd565b61038c6106753660046144b8565b6118e3565b348015610685575f80fd5b5061038c610694366004614217565b611be2565b3480156106a4575f80fd5b506102ae7f3c63e605be3290ab6b04cfc46c6e1516e626d43236b034f09d7ede1d017beb0c81565b3480156106d7575f80fd5b5061038c6106e6366004614530565b611c06565b3480156106f6575f80fd5b50601e54610309906001600160a01b031681565b348015610715575f80fd5b5061038c610724366004614279565b611e6e565b348015610734575f80fd5b506102ae5f80516020614c5a83398151915281565b348015610754575f80fd5b506102ae601a5481565b348015610769575f80fd5b50600354610309906001600160a01b031681565b5f6001600160e01b03198216635a05180f60e01b14806107a157506107a182611f1c565b92915050565b60605f8060115f016040516020016107bf919061458e565b60408051808303601f19018152919052601754909460ff8216945061010090910463ffffffff1692509050565b5f6107f681611f50565b601b8290556040518281527f8906f1615411c1be37bc832caf2d17b0903ad4624b9680d92fb9799b444f9aa2906020015b60405180910390a15050565b5f8281526020819052604090206001015461084d81611f50565b6108578383611f5a565b505050565b5f80516020614c5a83398151915261087381611f50565b6019546001600160401b031661088a6001846145c0565b6001600160401b0316146108b95760405162461bcd60e51b81526004016108b0906145e0565b60405180910390fd5b601980546fffffffffffffffff00000000000000001916600160401b6001600160401b038581168281029390931793849055604080519384529190930490921660208201527f6daa220d3e9550bfb5df36368059f0ad2708facf48ccc8248a632dc4ad81d13c9101610827565b5f80516020614c5a83398151915261093d81611f50565b604080516101208101909152610a0e9060098160a08101828160e084018260028282826020028201915b81548152602001906001019080831161096757505050918352505060408051808201918290526020909201919060028481019182845b81548152602001906001019080831161099d57505050919092525050508152604080518082018252600484015481526005840154602080830191909152830152600683015460ff811691830191909152610100900463ffffffff166060820152600790910154608090910152611f7b565b15610a5a57610a1b611f95565b601754610a3490610100900463ffffffff166001614621565b600f805463ffffffff929092166101000264ffffffff0019909216919091179055610a95565b600f54610a7390610100900463ffffffff166001614621565b600f805463ffffffff929092166101000264ffffffff00199092169190911790555b610a9e5f6120a4565b50565b6001600160a01b0381163314610b115760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084016108b0565b610b1b828261219f565b5050565b601c544211610b7f5760405162461bcd60e51b815260206004820152602660248201527f476f764272696467653a206e6f7420656e6f7567682074696d6520616674657260448201526520726574727960d01b60648201526084016108b0565b601b54601a54610b8f919061463e565b4211610bec5760405162461bcd60e51b815260206004820152602660248201527f476f764272696467653a206e6f7420656e6f7567682074696d65206166746572604482015265040cae0dec6d60d31b60648201526084016108b0565b601d54610bf9904261463e565b601c55600f546019546040805161010090930463ffffffff1683526001600160401b0390911660208301527ffcd60c668a304ac5a7450e369d6196673b3637ecf20947a69afa95ae9359b290910160405180910390a1565b60068054610c5e90614651565b80601f0160208091040260200160405190810160405280929190818152602001828054610c8a90614651565b8015610cd55780601f10610cac57610100808354040283529160200191610cd5565b820191905f5260205f20905b815481529060010190602001808311610cb857829003601f168201915b505050505081565b5f80516020614c5a833981519152610cf481611f50565b6001600160a01b038216610d435760405162461bcd60e51b815260206004820152601660248201527542726964676556333a207a65726f206164647265737360501b60448201526064016108b0565b600480546001600160a01b0319166001600160a01b0384169081179091556040519081527f6536690106168bdf4ba72c128a053d817999b1db90cae23f139b293bf862cb7590602001610827565b60058054610c5e90614651565b5f80516020614c5a833981519152610db581611f50565b6007805483919060ff19166001836002811115610dd457610dd461447e565b02179055506007546040517fc635bb75c392e81c891d50372a48cfa81b6799ac6d594cb4c28a8c5e8bef6e9b916108279160ff90911690614492565b5f610e1a81611f50565b601d8290556040518281527f85b47f19cf7d13a9f8bfebfa580d1b080f93326645845e92716924630a0be77190602001610827565b5f8082806020019051810190610e659190614683565b6004549091505f906001600160a01b031663095c1566610e8b6080890160608a01614241565b610e9860208a018a6146a6565b60405160e085901b6001600160e01b03191681526001600160401b03909316600484015260248301525063ffffffff851660448201526064016040805180830381865afa158015610eeb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f0f91906146e8565b509695505050505050565b5f80516020614c5a833981519152610f3181611f50565b6001600160a01b038216610f805760405162461bcd60e51b815260206004820152601660248201527542726964676556333a207a65726f206164647265737360501b60448201526064016108b0565b600380546001600160a01b0319166001600160a01b0384169081179091556040519081527fb68fd1a788a85f8f18de7976d851969ff9ff2216de81169c17a6f4ac94c23def90602001610827565b5f7f21702c8af46127c7fa207f89d0b0a8441bb32959a0ac7df790e9ab1a25c98926610ff981611f50565b6110016121c0565b600160075460ff16600281111561101a5761101a61447e565b036110605760405162461bcd60e51b81526020600482015260166024820152754272696467653a20737461746520696e61637469766560501b60448201526064016108b0565b5f5b8381101561174f575f6110a18686848181106110805761108061470a565b9050602002810190611092919061471e565b61109c90806146a6565b612217565b60105490915081036111c857604080516101208101918290526009805460e0830190815261117993839160a0830191849183918390600290600a61010089018083116109675750505091835250506040805180820191829052600284810180548352602094850194929390926003870190850180831161099d57505050919092525050508152604080518082018252600484015481526005840154602080830191909152830152600683015460ff811691830191909152610100900463ffffffff166060820152600790910154608090910152611f7b565b6111955760405162461bcd60e51b81526004016108b09061473c565b6111c360098787858181106111ac576111ac61470a565b90506020028101906111be919061471e565b612262565b61130e565b60185481036112d057604080516101208101918290526011805460e0830190815261129d93839160a0830191849183918390600290601261010089018083116109675750505091835250506040805180820191829052600284810180548352602094850194929390926003870190850180831161099d57505050919092525050508152604080518082018252600484015481526005840154602080830191909152830152600683015460ff811691830191909152610100900463ffffffff166060820152600790910154608090910152611f7b565b6112b95760405162461bcd60e51b81526004016108b09061473c565b6111c360118787858181106111ac576111ac61470a565b60405162461bcd60e51b8152602060048201526013602482015272084e4d2c8ceca7440eee4dedcce40cae0dec6d606b1b60448201526064016108b0565b5f6113b58787858181106113245761132461470a565b9050602002810190611336919061471e565b6113449060208101906146a6565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506113b092508b91508a90508781811061138f5761138f61470a565b90506020028101906113a1919061471e565b6113ab90806146a6565b61235b565b61236d565b90505f805f806113c4856124a0565b935093509350935046816001600160401b03161461141d5760405162461bcd60e51b8152602060048201526016602482015275109c9a5919d94e881ddc9bdb99c818da185a5b881a5960521b60448201526064016108b0565b5f8481526008602052604090205460ff161561147b5760405162461bcd60e51b815260206004820152601f60248201527f4272696467653a207265717565737420696420616c7265616479207365656e0060448201526064016108b0565b5f848152600860205260408120805460ff1916600190811790915584516114a2919061476b565b9050806001600160401b038111156114bc576114bc6142c6565b6040519080825280601f01601f1916602001820160405280156114e6576020820181803683370190505b5095505f5b81811015611548578481815181106115055761150561470a565b602001015160f81c60f81b8782815181106115225761152261470a565b60200101906001600160f81b03191690815f1a9053506115418161477e565b90506114eb565b508360018551611558919061476b565b815181106115685761156861470a565b01602001516001600160f81b031916600160f81b0361166f5785516080146115d25760405162461bcd60e51b815260206004820152601e60248201527f4272696467653a20496e76616c6964206d657373616765206c656e677468000060448201526064016108b0565b5f805f868060200190518101906115e99190614796565b50600354604051632c7f327760e11b8152600481018490526001600160401b038316602482015260448101859052606481018d905293965091945092506001600160a01b0316906358fe64ee906084015b5f604051808303815f87803b158015611651575f80fd5b505af1158015611663573d5f803e3d5ffd5b50505050505050611737565b836001855161167e919061476b565b8151811061168e5761168e61470a565b01602001516001600160f81b0319165f036116f7575f805f868060200190518101906116ba91906147c9565b5060035460405163f137538b60e01b815293965091945092506001600160a01b03169063f137538b9061163a908590859088908e90600401614854565b60405162461bcd60e51b81526020600482015260156024820152744272696467653a2077726f6e67206d65737361676560581b60448201526064016108b0565b50505050505050806117489061477e565b9050611062565b506001915061175e6001600255565b5092915050565b5f82815260016020526040812061177c90836124ec565b9392505050565b5f61178d81611f50565b6040515f90339084908381818185875af1925050503d805f81146117cc576040519150601f19603f3d011682016040523d82523d5f602084013e6117d1565b606091505b50509050806118225760405162461bcd60e51b815260206004820152601e60248201527f42726964676556333a206661696c656420746f2073656e64204574686572000060448201526064016108b0565b60408051338152602081018590527f810f4216b8f4ed8460c9944d3a3bee30521ce371329120f4cf59fad7ffd2e081910160405180910390a1505050565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60605f8060095f016040516020016118a0919061458e565b60408051808303601f19018152919052600f54909460ff8216945061010090910463ffffffff1692509050565b5f8181526001602052604081206107a1906124f7565b7f3c63e605be3290ab6b04cfc46c6e1516e626d43236b034f09d7ede1d017beb0c61190d81611f50565b5f60075460ff1660028111156119255761192561447e565b1461196b5760405162461bcd60e51b81526020600482015260166024820152754272696467653a20737461746520696e61637469766560501b60448201526064016108b0565b604080516101208101918290526011805460e08301908152611a3793839160a0830191849183918390600290601261010089018083116109675750505091835250506040805180820191829052600284810180548352602094850194929390926003870190850180831161099d57505050919092525050508152604080518082018252600484015481526005840154602080830191909152830152600683015460ff811691830191909152610100900463ffffffff166060820152600790910154608090910152611f7b565b80611b095750604080516101208101918290526009805460e08301908152611b0993839160a0830191849183918390600290600a61010089018083116109675750505091835250506040805180820191829052600284810180548352602094850194929390926003870190850180831161099d57505050919092525050508152604080518082018252600484015481526005840154602080830191909152830152600683015460ff811691830191909152610100900463ffffffff166060820152600790910154608090910152611f7b565b611b255760405162461bcd60e51b81526004016108b09061473c565b60408501357f5566d73d091d945ab32ea023cd1930c0d43aa43bef9aee4cb029775cfc94bdae8635611b5a60208901896146a6565b84611b6b60808c0160608d01614241565b604051611b7c95949392919061488c565b60405180910390a17f3486f12e81927998a69cd0e6cd3978f4b1260266edb68145d92c6a32e080ddb3865f013584806020019051810190611bbd9190614683565b6040805192835263ffffffff90911660208301520160405180910390a1505050505050565b5f82815260208190526040902060010154611bfc81611f50565b610857838361219f565b7f21702c8af46127c7fa207f89d0b0a8441bb32959a0ac7df790e9ab1a25c98926611c3081611f50565b5f611c84611c4160208501856146a6565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506113b092506113ab9150879050806146a6565b90505f805f80611c9385612500565b600f549397509195509350915063ffffffff80851691611cbb91610100909104166001614621565b63ffffffff1614611d0e5760405162461bcd60e51b815260206004820152601a60248201527f4272696467653a2077726f6e672065706f6368206e756d62657200000000000060448201526064016108b0565b604080516101208101918290526009805460e08301908152611dda93839160a0830191849183918390600290600a61010089018083116109675750505091835250506040805180820191829052600284810180548352602094850194929390926003870190850180831161099d57505050919092525050508152604080518082018252600484015481526005840154602080830191909152830152600683015460ff811691830191909152610100900463ffffffff166060820152600790910154608090910152611f7b565b15611df257611dea600988612262565b611df2611f95565b5f6002611dff89806146a6565b604051611e0d9291906148e4565b602060405180830381855afa158015611e28573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190611e4b91906148f3565b9050611e5b60098484878561254a565b611e64856120a4565b5050505050505050565b5f611e7881611f50565b6001600160a01b038216611ece5760405162461bcd60e51b815260206004820152601d60248201527f476f764272696467653a207a65726f206164647265737320676976656e00000060448201526064016108b0565b601e80546001600160a01b0319166001600160a01b0384169081179091556040519081527fef697ae2a61f63e7a8cb0d7e7a6c0a794c764a208b7d0360e47c241b14a0dbd990602001610827565b5f6001600160e01b03198216637965db0b60e01b14806107a157506301ffc9a760e01b6001600160e01b03198316146107a1565b610a9e813361264c565b611f6482826126a5565b5f8281526001602052604090206108579082612728565b805151515f901515806107a1575050515160200151151590565b600960118181611fa781836002613ffc565b50611fba60028281019084810190613ffc565b505050600482810154908201556005808301549082015560068083018054918301805460ff19811660ff9094169384178255915463ffffffff61010091829004160264ffffffffff1990921690921717905560079182015491015561201d614037565b80518051829160099182906120359082906002614084565b50602082015161204b9060028084019190614084565b50505060208281015180516004840155015160058201556040820151600682018054606085015163ffffffff166101000264ffffffffff1990911660ff9093169290921791909117905560809091015160079091015550565b6019546001600160401b03908116908216156120db576019805467ffffffffffffffff19166001600160401b038416179055612100565b60198054600160401b81046001600160401b031667ffffffffffffffff199091161790555b6019546001600160401b038083169116101561212e5760405162461bcd60e51b81526004016108b0906145e0565b42601a556040517f7abd871edc50e0783b456da5e3441224a90207257b5a02f5b2410f905204e0c0906121669060099060200161458e565b60408051808303601f1901815290829052600f546019546108279361010090920463ffffffff16916001600160401b039091169061490a565b6121a9828261273c565b5f82815260016020526040902061085790826127a0565b60028054036122115760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108b0565b60028055565b5f61177c612229604860288587614941565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506127b492505050565b604080516101208101909152610b1b90838160a08101828160e084018260028282826020028201915b81548152602001906001019080831161228b57505050918352505060408051808201918290526020909201919060028481019182845b8154815260200190600101908083116122c157505050919092525050508152604080518082018252600484015481526005840154602080830191909152830152600683015460ff811691830191909152610100900463ffffffff16606082015260079091015460809091015261233783806146a6565b61234460408601866146a6565b61235160608801886146a6565b886080013561280e565b5f61177c612229606860488587614941565b60605f606061237c85836129dc565b925090505f61238a82612aec565b90505f602184885161239c919061476b565b6123a6919061497c565b90505f805f5b8381101561244e576123be8a88612b5a565b975091506123cc8a88612c12565b9750925060ff82165f036123eb576123e48386612c9e565b945061243c565b8160ff16600103612400576123e48584612c9e565b60405162461bcd60e51b815260206004820152601160248201527013595c9adb194e881c1c9bdd9948195bd9607a1b60448201526064016108b0565b806124468161477e565b9150506123ac565b508784146124935760405162461bcd60e51b815260206004820152601260248201527113595c9adb194e881c1c9bdd99481c9bdbdd60721b60448201526064016108b0565b5092979650505050505050565b5f60605f805f6124b08682612c12565b90955090506124bf8682612d19565b90925090506124ce8682612de7565b90935090506124dd86826129dc565b50949694955091939092509050565b5f61177c8383612e7e565b5f6107a1825490565b5f80606081806125108682612d19565b909550905061251f8682612ea4565b909450905061252e8682612b5a565b909250905061253d86826129dc565b5094969395509092915050565b5f61255485612f72565b90505f60405180604001604052805f81526020015f81525090505f80835f015184602001518360405160200161258c939291906149b1565b60405160208183030381529060405290505b8660ff168210156125d5578160a08201526125c1836125bc83612fae565b61306a565b9250816125cd8161477e565b92505061259e565b835184908a906125e89082906002614084565b5060208201516125fe9060028084019190614084565b5050835160048b01555050506020015160058701555060068501805463ffffffff9093166101000264ffffffffff1990931660ff909416939093179190911790915560079092019190915550565b6126568282611860565b610b1b5761266381613105565b61266e836020613117565b60405160200161267f9291906149d9565b60408051601f198184030181529082905262461bcd60e51b82526108b091600401614267565b6126af8282611860565b610b1b575f828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556126e43390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b5f61177c836001600160a01b0384166132ac565b6127468282611860565b15610b1b575f828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b5f61177c836001600160a01b0384166132f8565b5f81516020146128065760405162461bcd60e51b815260206004820152601760248201527f6279746573206c656e677468206973206e6f742033322e00000000000000000060448201526064016108b0565b506020015190565b6003886040015160ff1660026128249190614a4d565b61282e919061497c565b612837826133db565b116128845760405162461bcd60e51b815260206004820152601e60248201527f426c6f636b3a206e6f7420656e6f756768207061727469636970616e7473000060448201526064016108b0565b876040015160ff1660ff14806128a45750876040015160ff166001901b81105b6128e95760405162461bcd60e51b8152602060048201526016602482015275426c6f636b3a206269746d61736b20746f6f2062696760501b60448201526064016108b0565b6129908886868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050604080516020601f8e018190048102820181019092528c815292508c91508b90819084018382808284375f9201919091525050604080516020601f8b0181900481028201810190925289815292508991508890819084018382808284375f92019190915250889250613409915050565b611e645760405162461bcd60e51b815260206004820152601860248201527f426c6f636b3a206d756c7469736967206d69736d61746368000000000000000060448201526064016108b0565b60605f806129ea8585613647565b86519095509091506129fc828661463e565b11158015612a125750612a0f818561463e565b84105b612a6a5760405162461bcd60e51b8152602060048201526024808201527f4e65787456617242797465732c206f66667365742065786365656473206d6178604482015263696d756d60e01b60648201526084016108b0565b606081158015612a885760405191505f825260208201604052612ad2565b6040519150601f8316801560200281840101848101888315602002848c0101015b81831015612ac1578051835260209283019201612aa9565b5050848452601f01601f1916604052505b5080612ade838761463e565b9350935050505b9250929050565b5f60025f83604051602001612b02929190614a64565b60408051601f1981840301815290829052612b1c91614a92565b602060405180830381855afa158015612b37573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906107a191906148f3565b5f808351836001612b6b919061463e565b11158015612b825750612b7f83600161463e565b83105b612bd85760405162461bcd60e51b815260206004820152602160248201527f4e65787455696e74382c204f66667365742065786365656473206d6178696d756044820152606d60f81b60648201526084016108b0565b5f60405184602087010151805f1a82535060018101604052601f81035191505080846001612c06919061463e565b92509250509250929050565b5f808351836020612c23919061463e565b11158015612c3a5750612c3783602061463e565b83105b612c865760405162461bcd60e51b815260206004820181905260248201527f4e657874486173682c206f66667365742065786365656473206d6178696d756d60448201526064016108b0565b5f60208401850151905080846020612c06919061463e565b604051600160f81b602082015260218101839052604181018290525f9060029060610160408051601f1981840301815290829052612cdb91614a92565b602060405180830381855afa158015612cf6573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061177c91906148f3565b5f808351836008612d2a919061463e565b11158015612d415750612d3e83600861463e565b83105b612d985760405162461bcd60e51b815260206004820152602260248201527f4e65787455696e7436342c206f66667365742065786365656473206d6178696d604482015261756d60f01b60648201526084016108b0565b5f60405160085f600182038760208a0101515b83831015612dcb5780821a83860153600183019250600182039150612dab565b505050016040819052601f190151905080612c0685600861463e565b5f808351836014612df8919061463e565b11158015612e0f5750612e0c83601461463e565b83105b612e675760405162461bcd60e51b815260206004820152602360248201527f4e657874416464726573732c206f66667365742065786365656473206d6178696044820152626d756d60e81b60648201526084016108b0565b83830160200151606081901c612c0685601461463e565b5f825f018281548110612e9357612e9361470a565b905f5260205f200154905092915050565b5f808351836004612eb5919061463e565b11158015612ecc5750612ec983600461463e565b83105b612f235760405162461bcd60e51b815260206004820152602260248201527f4e65787455696e7433322c206f66667365742065786365656473206d6178696d604482015261756d60f01b60648201526084016108b0565b5f60405160045f600182038760208a0101515b83831015612f565780821a83860153600183019250600182039150612f36565b505050016040819052601f190151905080612c0685600461463e565b612f7a6140b2565b6020828101516040840151606085015160809095015184519290925283518301528282018051949094529251019190915290565b604080518082019091525f80825260208201525f600283604051612fd29190614a92565b602060405180830381855afa158015612fed573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061301091906148f3565b90505f61302a5f80516020614c3a83398151915283614aa3565b90505f5b6130378261379b565b90508015613058576040805180820190915291825260208201529392505050565b61306360018361463e565b915061302e565b604080518082019091525f80825260208201526130856140d7565b835181526020808501518183015283516040808401919091529084015160608301525f908360808460066107d05a03fa9050806130fd5760405162461bcd60e51b8152602060048201526016602482015275109b1cce88185919081c1bda5b9d1cc819985a5b195960521b60448201526064016108b0565b505092915050565b60606107a16001600160a01b03831660145b60605f613125836002614a4d565b61313090600261463e565b6001600160401b03811115613147576131476142c6565b6040519080825280601f01601f191660200182016040528015613171576020820181803683370190505b509050600360fc1b815f8151811061318b5761318b61470a565b60200101906001600160f81b03191690815f1a905350600f60fb1b816001815181106131b9576131b961470a565b60200101906001600160f81b03191690815f1a9053505f6131db846002614a4d565b6131e690600161463e565b90505b600181111561325d576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061321a5761321a61470a565b1a60f81b8282815181106132305761323061470a565b60200101906001600160f81b03191690815f1a90535060049490941c9361325681614ab6565b90506131e9565b50831561177c5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016108b0565b5f8181526001830160205260408120546132f157508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556107a1565b505f6107a1565b5f81815260018301602052604081205480156133d2575f61331a60018361476b565b85549091505f9061332d9060019061476b565b905081811461338c575f865f01828154811061334b5761334b61470a565b905f5260205f200154905080875f01848154811061336b5761336b61470a565b5f918252602080832090910192909255918252600188019052604090208390555b855486908061339d5761339d614acb565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f9055600193505050506107a1565b5f9150506107a1565b5f5b8115613404576133ee60018361476b565b90911690806133fc8161477e565b9150506133dd565b919050565b60208086015186518051908301516040515f948593600193859361342f938591016149b1565b60405160208183030381529060405290505b896040015160ff16831015613490578186165f03613477578260a0820152613474846125bc61346f84612fae565b6137d5565b93505b60019190911b90826134888161477e565b935050613441565b604080516003808252608082019092525f91816020015b604080518082019091525f80825260208201528152602001906001900390816134a7575050604080516003808252608082019092529192505f9190602082015b6134ef6140b2565b8152602001906001900390816134e75750506040805180820182525f80825260208083019182528d0151928d015192825291909152909150613530906137d5565b825f815181106135425761354261470a565b6020908102919091018101919091528c518051908201516040516135829361356e9392918f9101614adf565b604051602081830303815290604052612fae565b826001815181106135955761359561470a565b602002602001018190525085826002815181106135b4576135b461470a565b60200260200101819052506135c761385e565b815f815181106135d9576135d961470a565b60200260200101819052506135ed8b612f72565b816001815181106136005761360061470a565b60200260200101819052508b5f0151816002815181106136225761362261470a565b6020026020010181905250613637828261391e565b9c9b505050505050505050505050565b5f805f6136548585612b5a565b945090505f60ff821660fd036136e15761366e8686613c73565b955061ffff16905060fd8110801590613689575061ffff8111155b6136d55760405162461bcd60e51b815260206004820152601f60248201527f4e65787455696e7431362c2076616c7565206f7574736964652072616e67650060448201526064016108b0565b9250839150612ae59050565b8160ff1660fe03613731576136f68686612ea4565b955063ffffffff16905061ffff81118015613715575063ffffffff8111155b6136d55760405162461bcd60e51b81526004016108b090614b19565b8160ff1660ff03613776576137468686612d19565b95506001600160401b0316905063ffffffff81116136d55760405162461bcd60e51b81526004016108b090614b19565b5060ff811660fd81106136d55760405162461bcd60e51b81526004016108b090614b19565b5f6107a15f80516020614c3a833981519152806137ba85600383613d29565b6137c590600361463e565b6137cf9190614aa3565b90613d71565b604080518082019091525f80825260208201526137f182613f46565b1561380e575050604080518082019091525f808252602082015290565b6040518060400160405280835f015181526020015f80516020614c3a833981519152846020015161383f9190614aa3565b613856905f80516020614c3a83398151915261476b565b905292915050565b6138666140b2565b50604080516080810182527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c28183019081527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6060830152815281518083019092527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b82527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa60208381019190915281019190915290565b5f81518351146139705760405162461bcd60e51b815260206004820152601960248201527f426c733a20706f696e7420636f756e74206d69736d617463680000000000000060448201526064016108b0565b82515f61397e826006614a4d565b90505f816001600160401b03811115613999576139996142c6565b6040519080825280602002602001820160405280156139c2578160200160208202803683370190505b5090505f5b83811015613bf9578681815181106139e1576139e161470a565b60200260200101515f0151828260066139fa9190614a4d565b613a04905f61463e565b81518110613a1457613a1461470a565b602002602001018181525050868181518110613a3257613a3261470a565b60200260200101516020015182826006613a4c9190614a4d565b613a5790600161463e565b81518110613a6757613a6761470a565b602002602001018181525050858181518110613a8557613a8561470a565b6020908102919091010151515182613a9e836006614a4d565b613aa990600261463e565b81518110613ab957613ab961470a565b602002602001018181525050858181518110613ad757613ad761470a565b60209081029190910181015151015182613af2836006614a4d565b613afd90600361463e565b81518110613b0d57613b0d61470a565b602002602001018181525050858181518110613b2b57613b2b61470a565b6020026020010151602001515f60028110613b4857613b4861470a565b602002015182613b59836006614a4d565b613b6490600461463e565b81518110613b7457613b7461470a565b602002602001018181525050858181518110613b9257613b9261470a565b602002602001015160200151600160028110613bb057613bb061470a565b602002015182613bc1836006614a4d565b613bcc90600561463e565b81518110613bdc57613bdc61470a565b602090810291909101015280613bf18161477e565b9150506139c7565b50613c026140f5565b5f602082602086026020860160086107d05a03fa905080613c655760405162461bcd60e51b815260206004820152601d60248201527f426c733a2070616972696e67206f7065726174696f6e206661696c656400000060448201526064016108b0565b505115159695505050505050565b5f808351836002613c84919061463e565b11158015613c9b5750613c9883600261463e565b83105b613cf25760405162461bcd60e51b815260206004820152602260248201527f4e65787455696e7431362c206f66667365742065786365656473206d6178696d604482015261756d60f01b60648201526084016108b0565b5f604051846020870101518060011a8253805f1a60018301535060028101604052601e81035191505080846002612c06919061463e565b5f6040516020810160208152602080820152602060408201528560608201528460808201528360a082015260208260c08360055f19fa613d67575f80fd5b5051949350505050565b5f613d7c8383613f5b565b600114613d8a57505f6107a1565b825f03613d9857505f6107a1565b613da3600483614aa3565b600303613dd257613dcb836004613dbb85600161463e565b613dc5919061497c565b84613d29565b90506107a1565b5f613dde60018461476b565b90505f5b613ded600283614aa3565b5f03613e1257613dfe60028361497c565b9150613e0b81600161463e565b9050613de2565b60025b613e1f8186613f5b565b5f1914613e3857613e3181600161463e565b9050613e15565b5f613e5a876002613e4a87600161463e565b613e54919061497c565b88613d29565b90505f613e68888689613d29565b90505f613e7684878a613d29565b9050845f80845b505f9050845b83821015613eb35760018114613eb357613e9f8160028e613d29565b905081613eab8161477e565b925050613e83565b815f03613ecc57869a50505050505050505050506107a1565b613ef7856001613edc858861476b565b613ee6919061476b565b613ef1906002614c2e565b8e613d29565b92508b613f048480614a4d565b613f0e9190614aa3565b94508b613f1b8489614a4d565b613f259190614aa3565b96508b613f328688614a4d565b613f3c9190614aa3565b9550819350613e7d565b80515f901580156107a1575050602001511590565b5f80613f7e846002613f6e60018761476b565b613f78919061497c565b85613d29565b9050801580613f8d5750806001145b15613f995790506107a1565b613fa460018461476b565b8103613fb4575f199150506107a1565b60405162461bcd60e51b815260206004820152601d60248201527f4661696c656420746f2063616c63756c617465206c6567656e6472652e00000060448201526064016108b0565b8260028101928215614027579182015b8281111561402757825482559160010191906001019061400c565b50614033929150614113565b5090565b6040518060a0016040528061404a6140b2565b815260200161406a60405180604001604052805f81526020015f81525090565b81525f602082018190526040820181905260609091015290565b8260028101928215614027579160200282015b82811115614027578251825591602001919060010190614097565b60405180604001604052806140c5614127565b81526020016140d2614127565b905290565b60405180608001604052806004906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b80821115614033575f8155600101614114565b60405180604001604052806002906020820280368337509192915050565b5f60208284031215614155575f80fd5b81356001600160e01b03198116811461177c575f80fd5b5f5b8381101561418657818101518382015260200161416e565b50505f910152565b5f81518084526141a581602086016020860161416c565b601f01601f19169290920160200192915050565b606081525f6141cb606083018661418e565b905060ff8416602083015263ffffffff83166040830152949350505050565b5f602082840312156141fa575f80fd5b5035919050565b80356001600160a01b0381168114613404575f80fd5b5f8060408385031215614228575f80fd5b8235915061423860208401614201565b90509250929050565b5f60208284031215614251575f80fd5b81356001600160401b038116811461177c575f80fd5b602081525f61177c602083018461418e565b5f60208284031215614289575f80fd5b61177c82614201565b5f602082840312156142a2575f80fd5b81356003811061177c575f80fd5b5f608082840312156142c0575f80fd5b50919050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b0381118282101715614302576143026142c6565b604052919050565b5f6001600160401b03821115614322576143226142c6565b50601f01601f191660200190565b5f82601f83011261433f575f80fd5b813561435261434d8261430a565b6142da565b818152846020838601011115614366575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f60608486031215614394575f80fd5b83356001600160401b03808211156143aa575f80fd5b6143b6878388016142b0565b94506143c460208701614201565b935060408601359150808211156143d9575f80fd5b506143e686828701614330565b9150509250925092565b5f8060208385031215614401575f80fd5b82356001600160401b0380821115614417575f80fd5b818501915085601f83011261442a575f80fd5b813581811115614438575f80fd5b8660208260051b850101111561444c575f80fd5b60209290920196919550909350505050565b5f806040838503121561446f575f80fd5b50508035926020909101359150565b634e487b7160e01b5f52602160045260245ffd5b60208101600383106144b257634e487b7160e01b5f52602160045260245ffd5b91905290565b5f805f80608085870312156144cb575f80fd5b84356001600160401b03808211156144e1575f80fd5b6144ed888389016142b0565b95506144fb60208801614201565b9450604087013593506060870135915080821115614517575f80fd5b5061452487828801614330565b91505092959194509250565b5f60208284031215614540575f80fd5b81356001600160401b03811115614555575f80fd5b820160a0818503121561177c575f80fd5b805f5b6002811015614588578154845260209093019260019182019101614569565b50505050565b6080810161459c8284614566565b6107a16040830160028501614566565b634e487b7160e01b5f52601160045260245ffd5b6001600160401b0382811682821603908082111561175e5761175e6145ac565b60208082526021908201527f476f764272696467653a2077726f6e672070726f746f636f6c2076657273696f6040820152603760f91b606082015260800190565b63ffffffff81811683821601908082111561175e5761175e6145ac565b808201808211156107a1576107a16145ac565b600181811c9082168061466557607f821691505b6020821081036142c057634e487b7160e01b5f52602260045260245ffd5b5f60208284031215614693575f80fd5b815163ffffffff8116811461177c575f80fd5b5f808335601e198436030181126146bb575f80fd5b8301803591506001600160401b038211156146d4575f80fd5b602001915036819003821315612ae5575f80fd5b5f80604083850312156146f9575f80fd5b505080516020909101519092909150565b634e487b7160e01b5f52603260045260245ffd5b5f8235609e19833603018112614732575f80fd5b9190910192915050565b602080825260159082015274109c9a5919d94e88195c1bd8da081b9bdd081cd95d605a1b604082015260600190565b818103818111156107a1576107a16145ac565b5f6001820161478f5761478f6145ac565b5060010190565b5f805f80608085870312156147a9575f80fd5b505082516020840151604085015160609095015191969095509092509050565b5f805f80608085870312156147dc575f80fd5b84516001600160401b038111156147f1575f80fd5b8501601f81018713614801575f80fd5b805161480f61434d8261430a565b818152886020838501011115614823575f80fd5b61483482602083016020860161416c565b60208801516040890151606090990151919a909950909650945050505050565b8481526001600160401b0384166020820152608060408201525f61487b608083018561418e565b905082606083015295945050505050565b85815260806020820152836080820152838560a08301375f60a08583018101919091526001600160a01b039390931660408201526001600160401b03919091166060820152601f909201601f19169091010192915050565b818382375f9101908152919050565b5f60208284031215614903575f80fd5b5051919050565b606081525f61491c606083018661418e565b905063ffffffff841660208301526001600160401b0383166040830152949350505050565b5f808585111561494f575f80fd5b8386111561495b575f80fd5b5050820193919092039150565b634e487b7160e01b5f52601260045260245ffd5b5f8261498a5761498a614968565b500490565b805f5b6002811015614588578151845260209384019390910190600101614992565b6149bb818561498f565b6149c8604082018461498f565b608081019190915260a00192915050565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f8351614a1081601785016020880161416c565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351614a4181602884016020880161416c565b01602801949350505050565b80820281158282048414176107a1576107a16145ac565b60ff60f81b8360f81b1681525f8251614a8481600185016020870161416c565b919091016001019392505050565b5f825161473281846020870161416c565b5f82614ab157614ab1614968565b500690565b5f81614ac457614ac46145ac565b505f190190565b634e487b7160e01b5f52603160045260245ffd5b614ae9818561498f565b614af6604082018461498f565b5f8251614b0a81608085016020870161416c565b91909101608001949350505050565b6020808252818101527f4e65787456617255696e742c2076616c7565206f7574736964652072616e6765604082015260600190565b600181815b80851115614b8857815f1904821115614b6e57614b6e6145ac565b80851615614b7b57918102915b93841c9390800290614b53565b509250929050565b5f82614b9e575060016107a1565b81614baa57505f6107a1565b8160018114614bc05760028114614bca57614be6565b60019150506107a1565b60ff841115614bdb57614bdb6145ac565b50506001821b6107a1565b5060208310610133831016604e8410600b8410161715614c09575081810a6107a1565b614c138383614b4e565b805f1904821115614c2657614c266145ac565b029392505050565b5f61177c8383614b9056fe30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4797667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929a264697066735822122067528910c06af1d73fd035bfa5aa7852f1bbc5e7b9230aceb35627e8155fc52e64736f6c63430008140033000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000044579776100000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x60806040526004361061023e575f3560e01c8063718da7ee11610134578063c49baebe116100b3578063d79de39e11610078578063d79de39e146106cc578063d9b5c4a5146106eb578063e1164b721461070a578063f5b541a614610729578063f60ca64114610749578063f7260d3e1461075e575f80fd5b8063c49baebe14610615578063ca15c87314610648578063d174ff8214610667578063d547741f1461067a578063d6fd317514610699575f80fd5b806391d14854116100f957806391d14854146105945780639a80fc66146105b3578063a217fddf146105c8578063b97dd9e2146105db578063c19d93fb146105ef575f80fd5b8063718da7ee146104ea57806379e99757146105095780638210a5bc146105285780639010d07c1461055657806391cdd9f014610575575f80fd5b80632ff1a529116101c0578063530e784f11610185578063530e784f1461045a57806354fd4d501461047957806356de96db1461048d5780635f1a6f05146104ac5780636e9cb097146104cb575f80fd5b80632ff1a529146103d357806331eab48a146103f257806336568abe14610406578063486a54f31461042557806351f9106614610439575f80fd5b806326339a211161020657806326339a21146103215780632ae9c600146103365780632ea940061461036d5780632f1874401461038e5780632f2ff15d146103b4575f80fd5b806301ffc9a714610242578063056768bf146102765780631bc2359a14610299578063248a9ca3146102bc5780632630c12f146102ea575b5f80fd5b34801561024d575f80fd5b5061026161025c366004614145565b61077d565b60405190151581526020015b60405180910390f35b348015610281575f80fd5b5061028a6107a7565b60405161026d939291906141b9565b3480156102a4575f80fd5b506102ae601b5481565b60405190815260200161026d565b3480156102c7575f80fd5b506102ae6102d63660046141ea565b5f9081526020819052604090206001015490565b3480156102f5575f80fd5b50600454610309906001600160a01b031681565b6040516001600160a01b03909116815260200161026d565b34801561032c575f80fd5b506102ae601c5481565b348015610341575f80fd5b50601954610355906001600160401b031681565b6040516001600160401b03909116815260200161026d565b348015610378575f80fd5b5061038c6103873660046141ea565b6107ec565b005b348015610399575f80fd5b5060195461035590600160401b90046001600160401b031681565b3480156103bf575f80fd5b5061038c6103ce366004614217565b610833565b3480156103de575f80fd5b5061038c6103ed366004614241565b61085c565b3480156103fd575f80fd5b5061038c610926565b348015610411575f80fd5b5061038c610420366004614217565b610aa1565b348015610430575f80fd5b5061038c610b1f565b348015610444575f80fd5b5061044d610c51565b60405161026d9190614267565b348015610465575f80fd5b5061038c610474366004614279565b610cdd565b348015610484575f80fd5b5061044d610d91565b348015610498575f80fd5b5061038c6104a7366004614292565b610d9e565b3480156104b7575f80fd5b5061038c6104c63660046141ea565b610e10565b3480156104d6575f80fd5b506102ae6104e5366004614382565b610e4f565b3480156104f5575f80fd5b5061038c610504366004614279565b610f1a565b348015610514575f80fd5b506102616105233660046143f0565b610fce565b348015610533575f80fd5b506102616105423660046141ea565b60086020525f908152604090205460ff1681565b348015610561575f80fd5b5061030961057036600461445e565b611765565b348015610580575f80fd5b5061038c61058f3660046141ea565b611783565b34801561059f575f80fd5b506102616105ae366004614217565b611860565b3480156105be575f80fd5b506102ae601d5481565b3480156105d3575f80fd5b506102ae5f81565b3480156105e6575f80fd5b5061028a611888565b3480156105fa575f80fd5b506007546106089060ff1681565b60405161026d9190614492565b348015610620575f80fd5b506102ae7f21702c8af46127c7fa207f89d0b0a8441bb32959a0ac7df790e9ab1a25c9892681565b348015610653575f80fd5b506102ae6106623660046141ea565b6118cd565b61038c6106753660046144b8565b6118e3565b348015610685575f80fd5b5061038c610694366004614217565b611be2565b3480156106a4575f80fd5b506102ae7f3c63e605be3290ab6b04cfc46c6e1516e626d43236b034f09d7ede1d017beb0c81565b3480156106d7575f80fd5b5061038c6106e6366004614530565b611c06565b3480156106f6575f80fd5b50601e54610309906001600160a01b031681565b348015610715575f80fd5b5061038c610724366004614279565b611e6e565b348015610734575f80fd5b506102ae5f80516020614c5a83398151915281565b348015610754575f80fd5b506102ae601a5481565b348015610769575f80fd5b50600354610309906001600160a01b031681565b5f6001600160e01b03198216635a05180f60e01b14806107a157506107a182611f1c565b92915050565b60605f8060115f016040516020016107bf919061458e565b60408051808303601f19018152919052601754909460ff8216945061010090910463ffffffff1692509050565b5f6107f681611f50565b601b8290556040518281527f8906f1615411c1be37bc832caf2d17b0903ad4624b9680d92fb9799b444f9aa2906020015b60405180910390a15050565b5f8281526020819052604090206001015461084d81611f50565b6108578383611f5a565b505050565b5f80516020614c5a83398151915261087381611f50565b6019546001600160401b031661088a6001846145c0565b6001600160401b0316146108b95760405162461bcd60e51b81526004016108b0906145e0565b60405180910390fd5b601980546fffffffffffffffff00000000000000001916600160401b6001600160401b038581168281029390931793849055604080519384529190930490921660208201527f6daa220d3e9550bfb5df36368059f0ad2708facf48ccc8248a632dc4ad81d13c9101610827565b5f80516020614c5a83398151915261093d81611f50565b604080516101208101909152610a0e9060098160a08101828160e084018260028282826020028201915b81548152602001906001019080831161096757505050918352505060408051808201918290526020909201919060028481019182845b81548152602001906001019080831161099d57505050919092525050508152604080518082018252600484015481526005840154602080830191909152830152600683015460ff811691830191909152610100900463ffffffff166060820152600790910154608090910152611f7b565b15610a5a57610a1b611f95565b601754610a3490610100900463ffffffff166001614621565b600f805463ffffffff929092166101000264ffffffff0019909216919091179055610a95565b600f54610a7390610100900463ffffffff166001614621565b600f805463ffffffff929092166101000264ffffffff00199092169190911790555b610a9e5f6120a4565b50565b6001600160a01b0381163314610b115760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084016108b0565b610b1b828261219f565b5050565b601c544211610b7f5760405162461bcd60e51b815260206004820152602660248201527f476f764272696467653a206e6f7420656e6f7567682074696d6520616674657260448201526520726574727960d01b60648201526084016108b0565b601b54601a54610b8f919061463e565b4211610bec5760405162461bcd60e51b815260206004820152602660248201527f476f764272696467653a206e6f7420656e6f7567682074696d65206166746572604482015265040cae0dec6d60d31b60648201526084016108b0565b601d54610bf9904261463e565b601c55600f546019546040805161010090930463ffffffff1683526001600160401b0390911660208301527ffcd60c668a304ac5a7450e369d6196673b3637ecf20947a69afa95ae9359b290910160405180910390a1565b60068054610c5e90614651565b80601f0160208091040260200160405190810160405280929190818152602001828054610c8a90614651565b8015610cd55780601f10610cac57610100808354040283529160200191610cd5565b820191905f5260205f20905b815481529060010190602001808311610cb857829003601f168201915b505050505081565b5f80516020614c5a833981519152610cf481611f50565b6001600160a01b038216610d435760405162461bcd60e51b815260206004820152601660248201527542726964676556333a207a65726f206164647265737360501b60448201526064016108b0565b600480546001600160a01b0319166001600160a01b0384169081179091556040519081527f6536690106168bdf4ba72c128a053d817999b1db90cae23f139b293bf862cb7590602001610827565b60058054610c5e90614651565b5f80516020614c5a833981519152610db581611f50565b6007805483919060ff19166001836002811115610dd457610dd461447e565b02179055506007546040517fc635bb75c392e81c891d50372a48cfa81b6799ac6d594cb4c28a8c5e8bef6e9b916108279160ff90911690614492565b5f610e1a81611f50565b601d8290556040518281527f85b47f19cf7d13a9f8bfebfa580d1b080f93326645845e92716924630a0be77190602001610827565b5f8082806020019051810190610e659190614683565b6004549091505f906001600160a01b031663095c1566610e8b6080890160608a01614241565b610e9860208a018a6146a6565b60405160e085901b6001600160e01b03191681526001600160401b03909316600484015260248301525063ffffffff851660448201526064016040805180830381865afa158015610eeb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f0f91906146e8565b509695505050505050565b5f80516020614c5a833981519152610f3181611f50565b6001600160a01b038216610f805760405162461bcd60e51b815260206004820152601660248201527542726964676556333a207a65726f206164647265737360501b60448201526064016108b0565b600380546001600160a01b0319166001600160a01b0384169081179091556040519081527fb68fd1a788a85f8f18de7976d851969ff9ff2216de81169c17a6f4ac94c23def90602001610827565b5f7f21702c8af46127c7fa207f89d0b0a8441bb32959a0ac7df790e9ab1a25c98926610ff981611f50565b6110016121c0565b600160075460ff16600281111561101a5761101a61447e565b036110605760405162461bcd60e51b81526020600482015260166024820152754272696467653a20737461746520696e61637469766560501b60448201526064016108b0565b5f5b8381101561174f575f6110a18686848181106110805761108061470a565b9050602002810190611092919061471e565b61109c90806146a6565b612217565b60105490915081036111c857604080516101208101918290526009805460e0830190815261117993839160a0830191849183918390600290600a61010089018083116109675750505091835250506040805180820191829052600284810180548352602094850194929390926003870190850180831161099d57505050919092525050508152604080518082018252600484015481526005840154602080830191909152830152600683015460ff811691830191909152610100900463ffffffff166060820152600790910154608090910152611f7b565b6111955760405162461bcd60e51b81526004016108b09061473c565b6111c360098787858181106111ac576111ac61470a565b90506020028101906111be919061471e565b612262565b61130e565b60185481036112d057604080516101208101918290526011805460e0830190815261129d93839160a0830191849183918390600290601261010089018083116109675750505091835250506040805180820191829052600284810180548352602094850194929390926003870190850180831161099d57505050919092525050508152604080518082018252600484015481526005840154602080830191909152830152600683015460ff811691830191909152610100900463ffffffff166060820152600790910154608090910152611f7b565b6112b95760405162461bcd60e51b81526004016108b09061473c565b6111c360118787858181106111ac576111ac61470a565b60405162461bcd60e51b8152602060048201526013602482015272084e4d2c8ceca7440eee4dedcce40cae0dec6d606b1b60448201526064016108b0565b5f6113b58787858181106113245761132461470a565b9050602002810190611336919061471e565b6113449060208101906146a6565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506113b092508b91508a90508781811061138f5761138f61470a565b90506020028101906113a1919061471e565b6113ab90806146a6565b61235b565b61236d565b90505f805f806113c4856124a0565b935093509350935046816001600160401b03161461141d5760405162461bcd60e51b8152602060048201526016602482015275109c9a5919d94e881ddc9bdb99c818da185a5b881a5960521b60448201526064016108b0565b5f8481526008602052604090205460ff161561147b5760405162461bcd60e51b815260206004820152601f60248201527f4272696467653a207265717565737420696420616c7265616479207365656e0060448201526064016108b0565b5f848152600860205260408120805460ff1916600190811790915584516114a2919061476b565b9050806001600160401b038111156114bc576114bc6142c6565b6040519080825280601f01601f1916602001820160405280156114e6576020820181803683370190505b5095505f5b81811015611548578481815181106115055761150561470a565b602001015160f81c60f81b8782815181106115225761152261470a565b60200101906001600160f81b03191690815f1a9053506115418161477e565b90506114eb565b508360018551611558919061476b565b815181106115685761156861470a565b01602001516001600160f81b031916600160f81b0361166f5785516080146115d25760405162461bcd60e51b815260206004820152601e60248201527f4272696467653a20496e76616c6964206d657373616765206c656e677468000060448201526064016108b0565b5f805f868060200190518101906115e99190614796565b50600354604051632c7f327760e11b8152600481018490526001600160401b038316602482015260448101859052606481018d905293965091945092506001600160a01b0316906358fe64ee906084015b5f604051808303815f87803b158015611651575f80fd5b505af1158015611663573d5f803e3d5ffd5b50505050505050611737565b836001855161167e919061476b565b8151811061168e5761168e61470a565b01602001516001600160f81b0319165f036116f7575f805f868060200190518101906116ba91906147c9565b5060035460405163f137538b60e01b815293965091945092506001600160a01b03169063f137538b9061163a908590859088908e90600401614854565b60405162461bcd60e51b81526020600482015260156024820152744272696467653a2077726f6e67206d65737361676560581b60448201526064016108b0565b50505050505050806117489061477e565b9050611062565b506001915061175e6001600255565b5092915050565b5f82815260016020526040812061177c90836124ec565b9392505050565b5f61178d81611f50565b6040515f90339084908381818185875af1925050503d805f81146117cc576040519150601f19603f3d011682016040523d82523d5f602084013e6117d1565b606091505b50509050806118225760405162461bcd60e51b815260206004820152601e60248201527f42726964676556333a206661696c656420746f2073656e64204574686572000060448201526064016108b0565b60408051338152602081018590527f810f4216b8f4ed8460c9944d3a3bee30521ce371329120f4cf59fad7ffd2e081910160405180910390a1505050565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60605f8060095f016040516020016118a0919061458e565b60408051808303601f19018152919052600f54909460ff8216945061010090910463ffffffff1692509050565b5f8181526001602052604081206107a1906124f7565b7f3c63e605be3290ab6b04cfc46c6e1516e626d43236b034f09d7ede1d017beb0c61190d81611f50565b5f60075460ff1660028111156119255761192561447e565b1461196b5760405162461bcd60e51b81526020600482015260166024820152754272696467653a20737461746520696e61637469766560501b60448201526064016108b0565b604080516101208101918290526011805460e08301908152611a3793839160a0830191849183918390600290601261010089018083116109675750505091835250506040805180820191829052600284810180548352602094850194929390926003870190850180831161099d57505050919092525050508152604080518082018252600484015481526005840154602080830191909152830152600683015460ff811691830191909152610100900463ffffffff166060820152600790910154608090910152611f7b565b80611b095750604080516101208101918290526009805460e08301908152611b0993839160a0830191849183918390600290600a61010089018083116109675750505091835250506040805180820191829052600284810180548352602094850194929390926003870190850180831161099d57505050919092525050508152604080518082018252600484015481526005840154602080830191909152830152600683015460ff811691830191909152610100900463ffffffff166060820152600790910154608090910152611f7b565b611b255760405162461bcd60e51b81526004016108b09061473c565b60408501357f5566d73d091d945ab32ea023cd1930c0d43aa43bef9aee4cb029775cfc94bdae8635611b5a60208901896146a6565b84611b6b60808c0160608d01614241565b604051611b7c95949392919061488c565b60405180910390a17f3486f12e81927998a69cd0e6cd3978f4b1260266edb68145d92c6a32e080ddb3865f013584806020019051810190611bbd9190614683565b6040805192835263ffffffff90911660208301520160405180910390a1505050505050565b5f82815260208190526040902060010154611bfc81611f50565b610857838361219f565b7f21702c8af46127c7fa207f89d0b0a8441bb32959a0ac7df790e9ab1a25c98926611c3081611f50565b5f611c84611c4160208501856146a6565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506113b092506113ab9150879050806146a6565b90505f805f80611c9385612500565b600f549397509195509350915063ffffffff80851691611cbb91610100909104166001614621565b63ffffffff1614611d0e5760405162461bcd60e51b815260206004820152601a60248201527f4272696467653a2077726f6e672065706f6368206e756d62657200000000000060448201526064016108b0565b604080516101208101918290526009805460e08301908152611dda93839160a0830191849183918390600290600a61010089018083116109675750505091835250506040805180820191829052600284810180548352602094850194929390926003870190850180831161099d57505050919092525050508152604080518082018252600484015481526005840154602080830191909152830152600683015460ff811691830191909152610100900463ffffffff166060820152600790910154608090910152611f7b565b15611df257611dea600988612262565b611df2611f95565b5f6002611dff89806146a6565b604051611e0d9291906148e4565b602060405180830381855afa158015611e28573d5f803e3d5ffd5b5050506040513d601f19601f82011682018060405250810190611e4b91906148f3565b9050611e5b60098484878561254a565b611e64856120a4565b5050505050505050565b5f611e7881611f50565b6001600160a01b038216611ece5760405162461bcd60e51b815260206004820152601d60248201527f476f764272696467653a207a65726f206164647265737320676976656e00000060448201526064016108b0565b601e80546001600160a01b0319166001600160a01b0384169081179091556040519081527fef697ae2a61f63e7a8cb0d7e7a6c0a794c764a208b7d0360e47c241b14a0dbd990602001610827565b5f6001600160e01b03198216637965db0b60e01b14806107a157506301ffc9a760e01b6001600160e01b03198316146107a1565b610a9e813361264c565b611f6482826126a5565b5f8281526001602052604090206108579082612728565b805151515f901515806107a1575050515160200151151590565b600960118181611fa781836002613ffc565b50611fba60028281019084810190613ffc565b505050600482810154908201556005808301549082015560068083018054918301805460ff19811660ff9094169384178255915463ffffffff61010091829004160264ffffffffff1990921690921717905560079182015491015561201d614037565b80518051829160099182906120359082906002614084565b50602082015161204b9060028084019190614084565b50505060208281015180516004840155015160058201556040820151600682018054606085015163ffffffff166101000264ffffffffff1990911660ff9093169290921791909117905560809091015160079091015550565b6019546001600160401b03908116908216156120db576019805467ffffffffffffffff19166001600160401b038416179055612100565b60198054600160401b81046001600160401b031667ffffffffffffffff199091161790555b6019546001600160401b038083169116101561212e5760405162461bcd60e51b81526004016108b0906145e0565b42601a556040517f7abd871edc50e0783b456da5e3441224a90207257b5a02f5b2410f905204e0c0906121669060099060200161458e565b60408051808303601f1901815290829052600f546019546108279361010090920463ffffffff16916001600160401b039091169061490a565b6121a9828261273c565b5f82815260016020526040902061085790826127a0565b60028054036122115760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016108b0565b60028055565b5f61177c612229604860288587614941565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506127b492505050565b604080516101208101909152610b1b90838160a08101828160e084018260028282826020028201915b81548152602001906001019080831161228b57505050918352505060408051808201918290526020909201919060028481019182845b8154815260200190600101908083116122c157505050919092525050508152604080518082018252600484015481526005840154602080830191909152830152600683015460ff811691830191909152610100900463ffffffff16606082015260079091015460809091015261233783806146a6565b61234460408601866146a6565b61235160608801886146a6565b886080013561280e565b5f61177c612229606860488587614941565b60605f606061237c85836129dc565b925090505f61238a82612aec565b90505f602184885161239c919061476b565b6123a6919061497c565b90505f805f5b8381101561244e576123be8a88612b5a565b975091506123cc8a88612c12565b9750925060ff82165f036123eb576123e48386612c9e565b945061243c565b8160ff16600103612400576123e48584612c9e565b60405162461bcd60e51b815260206004820152601160248201527013595c9adb194e881c1c9bdd9948195bd9607a1b60448201526064016108b0565b806124468161477e565b9150506123ac565b508784146124935760405162461bcd60e51b815260206004820152601260248201527113595c9adb194e881c1c9bdd99481c9bdbdd60721b60448201526064016108b0565b5092979650505050505050565b5f60605f805f6124b08682612c12565b90955090506124bf8682612d19565b90925090506124ce8682612de7565b90935090506124dd86826129dc565b50949694955091939092509050565b5f61177c8383612e7e565b5f6107a1825490565b5f80606081806125108682612d19565b909550905061251f8682612ea4565b909450905061252e8682612b5a565b909250905061253d86826129dc565b5094969395509092915050565b5f61255485612f72565b90505f60405180604001604052805f81526020015f81525090505f80835f015184602001518360405160200161258c939291906149b1565b60405160208183030381529060405290505b8660ff168210156125d5578160a08201526125c1836125bc83612fae565b61306a565b9250816125cd8161477e565b92505061259e565b835184908a906125e89082906002614084565b5060208201516125fe9060028084019190614084565b5050835160048b01555050506020015160058701555060068501805463ffffffff9093166101000264ffffffffff1990931660ff909416939093179190911790915560079092019190915550565b6126568282611860565b610b1b5761266381613105565b61266e836020613117565b60405160200161267f9291906149d9565b60408051601f198184030181529082905262461bcd60e51b82526108b091600401614267565b6126af8282611860565b610b1b575f828152602081815260408083206001600160a01b03851684529091529020805460ff191660011790556126e43390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b5f61177c836001600160a01b0384166132ac565b6127468282611860565b15610b1b575f828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b5f61177c836001600160a01b0384166132f8565b5f81516020146128065760405162461bcd60e51b815260206004820152601760248201527f6279746573206c656e677468206973206e6f742033322e00000000000000000060448201526064016108b0565b506020015190565b6003886040015160ff1660026128249190614a4d565b61282e919061497c565b612837826133db565b116128845760405162461bcd60e51b815260206004820152601e60248201527f426c6f636b3a206e6f7420656e6f756768207061727469636970616e7473000060448201526064016108b0565b876040015160ff1660ff14806128a45750876040015160ff166001901b81105b6128e95760405162461bcd60e51b8152602060048201526016602482015275426c6f636b3a206269746d61736b20746f6f2062696760501b60448201526064016108b0565b6129908886868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525050604080516020601f8e018190048102820181019092528c815292508c91508b90819084018382808284375f9201919091525050604080516020601f8b0181900481028201810190925289815292508991508890819084018382808284375f92019190915250889250613409915050565b611e645760405162461bcd60e51b815260206004820152601860248201527f426c6f636b3a206d756c7469736967206d69736d61746368000000000000000060448201526064016108b0565b60605f806129ea8585613647565b86519095509091506129fc828661463e565b11158015612a125750612a0f818561463e565b84105b612a6a5760405162461bcd60e51b8152602060048201526024808201527f4e65787456617242797465732c206f66667365742065786365656473206d6178604482015263696d756d60e01b60648201526084016108b0565b606081158015612a885760405191505f825260208201604052612ad2565b6040519150601f8316801560200281840101848101888315602002848c0101015b81831015612ac1578051835260209283019201612aa9565b5050848452601f01601f1916604052505b5080612ade838761463e565b9350935050505b9250929050565b5f60025f83604051602001612b02929190614a64565b60408051601f1981840301815290829052612b1c91614a92565b602060405180830381855afa158015612b37573d5f803e3d5ffd5b5050506040513d601f19601f820116820180604052508101906107a191906148f3565b5f808351836001612b6b919061463e565b11158015612b825750612b7f83600161463e565b83105b612bd85760405162461bcd60e51b815260206004820152602160248201527f4e65787455696e74382c204f66667365742065786365656473206d6178696d756044820152606d60f81b60648201526084016108b0565b5f60405184602087010151805f1a82535060018101604052601f81035191505080846001612c06919061463e565b92509250509250929050565b5f808351836020612c23919061463e565b11158015612c3a5750612c3783602061463e565b83105b612c865760405162461bcd60e51b815260206004820181905260248201527f4e657874486173682c206f66667365742065786365656473206d6178696d756d60448201526064016108b0565b5f60208401850151905080846020612c06919061463e565b604051600160f81b602082015260218101839052604181018290525f9060029060610160408051601f1981840301815290829052612cdb91614a92565b602060405180830381855afa158015612cf6573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061177c91906148f3565b5f808351836008612d2a919061463e565b11158015612d415750612d3e83600861463e565b83105b612d985760405162461bcd60e51b815260206004820152602260248201527f4e65787455696e7436342c206f66667365742065786365656473206d6178696d604482015261756d60f01b60648201526084016108b0565b5f60405160085f600182038760208a0101515b83831015612dcb5780821a83860153600183019250600182039150612dab565b505050016040819052601f190151905080612c0685600861463e565b5f808351836014612df8919061463e565b11158015612e0f5750612e0c83601461463e565b83105b612e675760405162461bcd60e51b815260206004820152602360248201527f4e657874416464726573732c206f66667365742065786365656473206d6178696044820152626d756d60e81b60648201526084016108b0565b83830160200151606081901c612c0685601461463e565b5f825f018281548110612e9357612e9361470a565b905f5260205f200154905092915050565b5f808351836004612eb5919061463e565b11158015612ecc5750612ec983600461463e565b83105b612f235760405162461bcd60e51b815260206004820152602260248201527f4e65787455696e7433322c206f66667365742065786365656473206d6178696d604482015261756d60f01b60648201526084016108b0565b5f60405160045f600182038760208a0101515b83831015612f565780821a83860153600183019250600182039150612f36565b505050016040819052601f190151905080612c0685600461463e565b612f7a6140b2565b6020828101516040840151606085015160809095015184519290925283518301528282018051949094529251019190915290565b604080518082019091525f80825260208201525f600283604051612fd29190614a92565b602060405180830381855afa158015612fed573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061301091906148f3565b90505f61302a5f80516020614c3a83398151915283614aa3565b90505f5b6130378261379b565b90508015613058576040805180820190915291825260208201529392505050565b61306360018361463e565b915061302e565b604080518082019091525f80825260208201526130856140d7565b835181526020808501518183015283516040808401919091529084015160608301525f908360808460066107d05a03fa9050806130fd5760405162461bcd60e51b8152602060048201526016602482015275109b1cce88185919081c1bda5b9d1cc819985a5b195960521b60448201526064016108b0565b505092915050565b60606107a16001600160a01b03831660145b60605f613125836002614a4d565b61313090600261463e565b6001600160401b03811115613147576131476142c6565b6040519080825280601f01601f191660200182016040528015613171576020820181803683370190505b509050600360fc1b815f8151811061318b5761318b61470a565b60200101906001600160f81b03191690815f1a905350600f60fb1b816001815181106131b9576131b961470a565b60200101906001600160f81b03191690815f1a9053505f6131db846002614a4d565b6131e690600161463e565b90505b600181111561325d576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061321a5761321a61470a565b1a60f81b8282815181106132305761323061470a565b60200101906001600160f81b03191690815f1a90535060049490941c9361325681614ab6565b90506131e9565b50831561177c5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016108b0565b5f8181526001830160205260408120546132f157508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556107a1565b505f6107a1565b5f81815260018301602052604081205480156133d2575f61331a60018361476b565b85549091505f9061332d9060019061476b565b905081811461338c575f865f01828154811061334b5761334b61470a565b905f5260205f200154905080875f01848154811061336b5761336b61470a565b5f918252602080832090910192909255918252600188019052604090208390555b855486908061339d5761339d614acb565b600190038181905f5260205f20015f90559055856001015f8681526020019081526020015f205f9055600193505050506107a1565b5f9150506107a1565b5f5b8115613404576133ee60018361476b565b90911690806133fc8161477e565b9150506133dd565b919050565b60208086015186518051908301516040515f948593600193859361342f938591016149b1565b60405160208183030381529060405290505b896040015160ff16831015613490578186165f03613477578260a0820152613474846125bc61346f84612fae565b6137d5565b93505b60019190911b90826134888161477e565b935050613441565b604080516003808252608082019092525f91816020015b604080518082019091525f80825260208201528152602001906001900390816134a7575050604080516003808252608082019092529192505f9190602082015b6134ef6140b2565b8152602001906001900390816134e75750506040805180820182525f80825260208083019182528d0151928d015192825291909152909150613530906137d5565b825f815181106135425761354261470a565b6020908102919091018101919091528c518051908201516040516135829361356e9392918f9101614adf565b604051602081830303815290604052612fae565b826001815181106135955761359561470a565b602002602001018190525085826002815181106135b4576135b461470a565b60200260200101819052506135c761385e565b815f815181106135d9576135d961470a565b60200260200101819052506135ed8b612f72565b816001815181106136005761360061470a565b60200260200101819052508b5f0151816002815181106136225761362261470a565b6020026020010181905250613637828261391e565b9c9b505050505050505050505050565b5f805f6136548585612b5a565b945090505f60ff821660fd036136e15761366e8686613c73565b955061ffff16905060fd8110801590613689575061ffff8111155b6136d55760405162461bcd60e51b815260206004820152601f60248201527f4e65787455696e7431362c2076616c7565206f7574736964652072616e67650060448201526064016108b0565b9250839150612ae59050565b8160ff1660fe03613731576136f68686612ea4565b955063ffffffff16905061ffff81118015613715575063ffffffff8111155b6136d55760405162461bcd60e51b81526004016108b090614b19565b8160ff1660ff03613776576137468686612d19565b95506001600160401b0316905063ffffffff81116136d55760405162461bcd60e51b81526004016108b090614b19565b5060ff811660fd81106136d55760405162461bcd60e51b81526004016108b090614b19565b5f6107a15f80516020614c3a833981519152806137ba85600383613d29565b6137c590600361463e565b6137cf9190614aa3565b90613d71565b604080518082019091525f80825260208201526137f182613f46565b1561380e575050604080518082019091525f808252602082015290565b6040518060400160405280835f015181526020015f80516020614c3a833981519152846020015161383f9190614aa3565b613856905f80516020614c3a83398151915261476b565b905292915050565b6138666140b2565b50604080516080810182527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c28183019081527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6060830152815281518083019092527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b82527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa60208381019190915281019190915290565b5f81518351146139705760405162461bcd60e51b815260206004820152601960248201527f426c733a20706f696e7420636f756e74206d69736d617463680000000000000060448201526064016108b0565b82515f61397e826006614a4d565b90505f816001600160401b03811115613999576139996142c6565b6040519080825280602002602001820160405280156139c2578160200160208202803683370190505b5090505f5b83811015613bf9578681815181106139e1576139e161470a565b60200260200101515f0151828260066139fa9190614a4d565b613a04905f61463e565b81518110613a1457613a1461470a565b602002602001018181525050868181518110613a3257613a3261470a565b60200260200101516020015182826006613a4c9190614a4d565b613a5790600161463e565b81518110613a6757613a6761470a565b602002602001018181525050858181518110613a8557613a8561470a565b6020908102919091010151515182613a9e836006614a4d565b613aa990600261463e565b81518110613ab957613ab961470a565b602002602001018181525050858181518110613ad757613ad761470a565b60209081029190910181015151015182613af2836006614a4d565b613afd90600361463e565b81518110613b0d57613b0d61470a565b602002602001018181525050858181518110613b2b57613b2b61470a565b6020026020010151602001515f60028110613b4857613b4861470a565b602002015182613b59836006614a4d565b613b6490600461463e565b81518110613b7457613b7461470a565b602002602001018181525050858181518110613b9257613b9261470a565b602002602001015160200151600160028110613bb057613bb061470a565b602002015182613bc1836006614a4d565b613bcc90600561463e565b81518110613bdc57613bdc61470a565b602090810291909101015280613bf18161477e565b9150506139c7565b50613c026140f5565b5f602082602086026020860160086107d05a03fa905080613c655760405162461bcd60e51b815260206004820152601d60248201527f426c733a2070616972696e67206f7065726174696f6e206661696c656400000060448201526064016108b0565b505115159695505050505050565b5f808351836002613c84919061463e565b11158015613c9b5750613c9883600261463e565b83105b613cf25760405162461bcd60e51b815260206004820152602260248201527f4e65787455696e7431362c206f66667365742065786365656473206d6178696d604482015261756d60f01b60648201526084016108b0565b5f604051846020870101518060011a8253805f1a60018301535060028101604052601e81035191505080846002612c06919061463e565b5f6040516020810160208152602080820152602060408201528560608201528460808201528360a082015260208260c08360055f19fa613d67575f80fd5b5051949350505050565b5f613d7c8383613f5b565b600114613d8a57505f6107a1565b825f03613d9857505f6107a1565b613da3600483614aa3565b600303613dd257613dcb836004613dbb85600161463e565b613dc5919061497c565b84613d29565b90506107a1565b5f613dde60018461476b565b90505f5b613ded600283614aa3565b5f03613e1257613dfe60028361497c565b9150613e0b81600161463e565b9050613de2565b60025b613e1f8186613f5b565b5f1914613e3857613e3181600161463e565b9050613e15565b5f613e5a876002613e4a87600161463e565b613e54919061497c565b88613d29565b90505f613e68888689613d29565b90505f613e7684878a613d29565b9050845f80845b505f9050845b83821015613eb35760018114613eb357613e9f8160028e613d29565b905081613eab8161477e565b925050613e83565b815f03613ecc57869a50505050505050505050506107a1565b613ef7856001613edc858861476b565b613ee6919061476b565b613ef1906002614c2e565b8e613d29565b92508b613f048480614a4d565b613f0e9190614aa3565b94508b613f1b8489614a4d565b613f259190614aa3565b96508b613f328688614a4d565b613f3c9190614aa3565b9550819350613e7d565b80515f901580156107a1575050602001511590565b5f80613f7e846002613f6e60018761476b565b613f78919061497c565b85613d29565b9050801580613f8d5750806001145b15613f995790506107a1565b613fa460018461476b565b8103613fb4575f199150506107a1565b60405162461bcd60e51b815260206004820152601d60248201527f4661696c656420746f2063616c63756c617465206c6567656e6472652e00000060448201526064016108b0565b8260028101928215614027579182015b8281111561402757825482559160010191906001019061400c565b50614033929150614113565b5090565b6040518060a0016040528061404a6140b2565b815260200161406a60405180604001604052805f81526020015f81525090565b81525f602082018190526040820181905260609091015290565b8260028101928215614027579160200282015b82811115614027578251825591602001919060010190614097565b60405180604001604052806140c5614127565b81526020016140d2614127565b905290565b60405180608001604052806004906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b5b80821115614033575f8155600101614114565b60405180604001604052806002906020820280368337509192915050565b5f60208284031215614155575f80fd5b81356001600160e01b03198116811461177c575f80fd5b5f5b8381101561418657818101518382015260200161416e565b50505f910152565b5f81518084526141a581602086016020860161416c565b601f01601f19169290920160200192915050565b606081525f6141cb606083018661418e565b905060ff8416602083015263ffffffff83166040830152949350505050565b5f602082840312156141fa575f80fd5b5035919050565b80356001600160a01b0381168114613404575f80fd5b5f8060408385031215614228575f80fd5b8235915061423860208401614201565b90509250929050565b5f60208284031215614251575f80fd5b81356001600160401b038116811461177c575f80fd5b602081525f61177c602083018461418e565b5f60208284031215614289575f80fd5b61177c82614201565b5f602082840312156142a2575f80fd5b81356003811061177c575f80fd5b5f608082840312156142c0575f80fd5b50919050565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b0381118282101715614302576143026142c6565b604052919050565b5f6001600160401b03821115614322576143226142c6565b50601f01601f191660200190565b5f82601f83011261433f575f80fd5b813561435261434d8261430a565b6142da565b818152846020838601011115614366575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f60608486031215614394575f80fd5b83356001600160401b03808211156143aa575f80fd5b6143b6878388016142b0565b94506143c460208701614201565b935060408601359150808211156143d9575f80fd5b506143e686828701614330565b9150509250925092565b5f8060208385031215614401575f80fd5b82356001600160401b0380821115614417575f80fd5b818501915085601f83011261442a575f80fd5b813581811115614438575f80fd5b8660208260051b850101111561444c575f80fd5b60209290920196919550909350505050565b5f806040838503121561446f575f80fd5b50508035926020909101359150565b634e487b7160e01b5f52602160045260245ffd5b60208101600383106144b257634e487b7160e01b5f52602160045260245ffd5b91905290565b5f805f80608085870312156144cb575f80fd5b84356001600160401b03808211156144e1575f80fd5b6144ed888389016142b0565b95506144fb60208801614201565b9450604087013593506060870135915080821115614517575f80fd5b5061452487828801614330565b91505092959194509250565b5f60208284031215614540575f80fd5b81356001600160401b03811115614555575f80fd5b820160a0818503121561177c575f80fd5b805f5b6002811015614588578154845260209093019260019182019101614569565b50505050565b6080810161459c8284614566565b6107a16040830160028501614566565b634e487b7160e01b5f52601160045260245ffd5b6001600160401b0382811682821603908082111561175e5761175e6145ac565b60208082526021908201527f476f764272696467653a2077726f6e672070726f746f636f6c2076657273696f6040820152603760f91b606082015260800190565b63ffffffff81811683821601908082111561175e5761175e6145ac565b808201808211156107a1576107a16145ac565b600181811c9082168061466557607f821691505b6020821081036142c057634e487b7160e01b5f52602260045260245ffd5b5f60208284031215614693575f80fd5b815163ffffffff8116811461177c575f80fd5b5f808335601e198436030181126146bb575f80fd5b8301803591506001600160401b038211156146d4575f80fd5b602001915036819003821315612ae5575f80fd5b5f80604083850312156146f9575f80fd5b505080516020909101519092909150565b634e487b7160e01b5f52603260045260245ffd5b5f8235609e19833603018112614732575f80fd5b9190910192915050565b602080825260159082015274109c9a5919d94e88195c1bd8da081b9bdd081cd95d605a1b604082015260600190565b818103818111156107a1576107a16145ac565b5f6001820161478f5761478f6145ac565b5060010190565b5f805f80608085870312156147a9575f80fd5b505082516020840151604085015160609095015191969095509092509050565b5f805f80608085870312156147dc575f80fd5b84516001600160401b038111156147f1575f80fd5b8501601f81018713614801575f80fd5b805161480f61434d8261430a565b818152886020838501011115614823575f80fd5b61483482602083016020860161416c565b60208801516040890151606090990151919a909950909650945050505050565b8481526001600160401b0384166020820152608060408201525f61487b608083018561418e565b905082606083015295945050505050565b85815260806020820152836080820152838560a08301375f60a08583018101919091526001600160a01b039390931660408201526001600160401b03919091166060820152601f909201601f19169091010192915050565b818382375f9101908152919050565b5f60208284031215614903575f80fd5b5051919050565b606081525f61491c606083018661418e565b905063ffffffff841660208301526001600160401b0383166040830152949350505050565b5f808585111561494f575f80fd5b8386111561495b575f80fd5b5050820193919092039150565b634e487b7160e01b5f52601260045260245ffd5b5f8261498a5761498a614968565b500490565b805f5b6002811015614588578151845260209384019390910190600101614992565b6149bb818561498f565b6149c8604082018461498f565b608081019190915260a00192915050565b7f416363657373436f6e74726f6c3a206163636f756e742000000000000000000081525f8351614a1081601785016020880161416c565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351614a4181602884016020880161416c565b01602801949350505050565b80820281158282048414176107a1576107a16145ac565b60ff60f81b8360f81b1681525f8251614a8481600185016020870161416c565b919091016001019392505050565b5f825161473281846020870161416c565b5f82614ab157614ab1614968565b500690565b5f81614ac457614ac46145ac565b505f190190565b634e487b7160e01b5f52603160045260245ffd5b614ae9818561498f565b614af6604082018461498f565b5f8251614b0a81608085016020870161416c565b91909101608001949350505050565b6020808252818101527f4e65787456617255696e742c2076616c7565206f7574736964652072616e6765604082015260600190565b600181815b80851115614b8857815f1904821115614b6e57614b6e6145ac565b80851615614b7b57918102915b93841c9390800290614b53565b509250929050565b5f82614b9e575060016107a1565b81614baa57505f6107a1565b8160018114614bc05760028114614bca57614be6565b60019150506107a1565b60ff841115614bdb57614bdb6145ac565b50506001821b6107a1565b5060208310610133831016604e8410600b8410161715614c09575081810a6107a1565b614c138383614b4e565b805f1904821115614c2657614c266145ac565b029392505050565b5f61177c8383614b9056fe30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4797667070c54ef182b0f5858b034beac1b6f3089aa2d3188bb1e8929f4fa9b929a264697066735822122067528910c06af1d73fd035bfa5aa7852f1bbc5e7b9230aceb35627e8155fc52e64736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000044579776100000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : tag_ (string): Eywa
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [2] : 4579776100000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$1.27
Net Worth in S
Token Allocations
S
96.12%
ETH
2.69%
BNB
0.55%
Others
0.65%
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| SONIC | 96.12% | $0.070317 | 17.3319 | $1.22 | |
| ARB | 1.78% | $2,951.31 | 0.00000763 | $0.022505 | |
| OP | 0.60% | $2,951.87 | 0.00000259 | $0.007653 | |
| BSC | 0.55% | $885.26 | 0.00000781 | $0.00691 | |
| FRAXTAL | 0.43% | $0.99251 | 0.00553676 | $0.005495 | |
| ETH | 0.23% | $2,951.77 | 0.000000992194 | $0.002929 | |
| POL | 0.17% | $0.126031 | 0.017 | $0.002141 | |
| BASE | 0.08% | $2,951.22 | 0.000000327673 | $0.000967 | |
| GNO | 0.04% | $0.999625 | 0.00054865 | $0.000548 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.