Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
16787672 | 669 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
TelepathyRouter
Compiler Version
v0.8.16+commit.07a7930e
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
pragma solidity 0.8.16; import {UUPSUpgradeable} from "openzeppelin-contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {ILightClient} from "src/lightclient/interfaces/ILightClient.sol"; import {TelepathyStorage} from "./TelepathyStorage.sol"; import { ITelepathyReceiver, Message, MessageStatus, ITelepathyHandler, ITelepathyRouter } from "./interfaces/ITelepathy.sol"; import {TargetAMB} from "./TargetAMB.sol"; import {SourceAMB} from "./SourceAMB.sol"; import {TelepathyAccess} from "./TelepathyAccess.sol"; /// @title Telepathy Router /// @author Succinct Labs /// @notice Send and receive arbitrary messages from other chains. contract TelepathyRouter is SourceAMB, TargetAMB, TelepathyAccess, UUPSUpgradeable { /// @notice Returns current contract version. uint8 public constant VERSION = 1; /// @notice Prevents the implementation contract from being initialized outside of the upgradeable proxy. constructor() { _disableInitializers(); } /// @notice Initializes the contract and the parent contracts once. function initialize( uint32[] memory _sourceChainIds, address[] memory _lightClients, address[] memory _broadcasters, address _timelock, address _guardian, bool _sendingEnabled ) external initializer { __ReentrancyGuard_init(); __AccessControl_init(); _grantRole(GUARDIAN_ROLE, _guardian); _grantRole(TIMELOCK_ROLE, _timelock); _grantRole(DEFAULT_ADMIN_ROLE, _timelock); __UUPSUpgradeable_init(); require(_sourceChainIds.length == _lightClients.length); require(_sourceChainIds.length == _broadcasters.length); sourceChainIds = _sourceChainIds; for (uint32 i = 0; i < sourceChainIds.length; i++) { lightClients[sourceChainIds[i]] = ILightClient(_lightClients[i]); broadcasters[sourceChainIds[i]] = _broadcasters[i]; } sendingEnabled = _sendingEnabled; version = VERSION; } /// @notice Authorizes an upgrade for the implementation contract. function _authorizeUpgrade(address newImplementation) internal override onlyTimelock {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControlUpgradeable.sol"; import "../utils/ContextUpgradeable.sol"; import "../utils/StringsUpgradeable.sol"; import "../utils/introspection/ERC165Upgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ``` * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ``` * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. */ abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable { function __AccessControl_init() internal onlyInitializing { } function __AccessControl_init_unchained() internal onlyInitializing { } 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(IAccessControlUpgradeable).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 ", StringsUpgradeable.toHexString(account), " is missing role ", StringsUpgradeable.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()); } } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) pragma solidity ^0.8.0; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControlUpgradeable { /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {AccessControl-_setupRole}. */ event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) external view returns (bool); /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {AccessControl-_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) external view returns (bytes32); /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) external; /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) external; /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) external; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822ProxiableUpgradeable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeaconUpgradeable.sol"; import "../../interfaces/draft-IERC1822Upgradeable.sol"; import "../../utils/AddressUpgradeable.sol"; import "../../utils/StorageSlotUpgradeable.sol"; import "../utils/Initializable.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ * * @custom:oz-upgrades-unsafe-allow delegatecall */ abstract contract ERC1967UpgradeUpgradeable is Initializable { function __ERC1967Upgrade_init() internal onlyInitializing { } function __ERC1967Upgrade_init_unchained() internal onlyInitializing { } // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall( address newImplementation, bytes memory data, bool forceCall ) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { _functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS( address newImplementation, bytes memory data, bool forceCall ) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Emitted when the beacon is upgraded. */ event BeaconUpgraded(address indexed beacon); /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall( address newBeacon, bytes memory data, bool forceCall ) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { _functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data); } } /** * @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) private returns (bytes memory) { require(AddressUpgradeable.isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return AddressUpgradeable.verifyCallResult(success, returndata, "Address: low-level delegate call failed"); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeaconUpgradeable { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.0; import "../../interfaces/draft-IERC1822Upgradeable.sol"; import "../ERC1967/ERC1967UpgradeUpgradeable.sol"; import "./Initializable.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. * * _Available since v4.1._ */ abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable { function __UUPSUpgradeable_init() internal onlyInitializing { } function __UUPSUpgradeable_init_unchained() internal onlyInitializing { } /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment address private immutable __self = address(this); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { require(address(this) != __self, "Function must be called through delegatecall"); require(_getImplementation() == __self, "Function must be called through active proxy"); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall"); _; } /** * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual override notDelegated returns (bytes32) { return _IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ function upgradeTo(address newImplementation) external virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, new bytes(0), false); } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data, true); } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeTo} and {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal override onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @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 ReentrancyGuardUpgradeable is Initializable { // 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; function __ReentrancyGuard_init() internal onlyInitializing { __ReentrancyGuard_init_unchained(); } function __ReentrancyGuard_init_unchained() internal onlyInitializing { _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 This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol) pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ``` * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ */ library StorageSlotUpgradeable { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/MathUpgradeable.sol"; /** * @dev String operations. */ library StringsUpgradeable { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = MathUpgradeable.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, MathUpgradeable.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165Upgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable { function __ERC165_init() internal onlyInitializing { } function __ERC165_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165Upgradeable).interfaceId; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165Upgradeable { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library MathUpgradeable { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv( uint256 x, uint256 y, uint256 denominator, Rounding rounding ) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10**64) { value /= 10**64; result += 64; } if (value >= 10**32) { value /= 10**32; result += 32; } if (value >= 10**16) { value /= 10**16; result += 16; } if (value >= 10**8) { value /= 10**8; result += 8; } if (value >= 10**4) { value /= 10**4; result += 4; } if (value >= 10**2) { value /= 10**2; result += 2; } if (value >= 10**1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @title Bytes * @notice Bytes is a library for manipulating byte arrays. */ library Bytes { /** * @custom:attribution https://github.com/GNSPS/solidity-bytes-utils * @notice Slices a byte array with a given starting index and length. Returns a new byte array * as opposed to a pointer to the original array. Will throw if trying to slice more * bytes than exist in the array. * * @param _bytes Byte array to slice. * @param _start Starting index of the slice. * @param _length Length of the slice. * * @return Slice of the input byte array. */ function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { unchecked { require(_length + 31 >= _length, "slice_overflow"); require(_start + _length >= _start, "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; } /** * @notice Slices a byte array with a given starting index up to the end of the original byte * array. Returns a new array rathern than a pointer to the original. * * @param _bytes Byte array to slice. * @param _start Starting index of the slice. * * @return Slice of the input byte array. */ function slice(bytes memory _bytes, uint256 _start) internal pure returns (bytes memory) { if (_start >= _bytes.length) { return bytes(""); } return slice(_bytes, _start, _bytes.length - _start); } /** * @notice Converts a byte array into a nibble array by splitting each byte into two nibbles. * Resulting nibble array will be exactly twice as long as the input byte array. * * @param _bytes Input byte array to convert. * * @return Resulting nibble array. */ function toNibbles(bytes memory _bytes) internal pure returns (bytes memory) { uint256 bytesLength = _bytes.length; bytes memory nibbles = new bytes(bytesLength * 2); bytes1 b; for (uint256 i = 0; i < bytesLength; ) { b = _bytes[i]; nibbles[i * 2] = b >> 4; nibbles[i * 2 + 1] = b & 0x0f; unchecked { ++i; } } return nibbles; } /** * @notice Compares two byte arrays by comparing their keccak256 hashes. * * @param _bytes First byte array to compare. * @param _other Second byte array to compare. * * @return True if the two byte arrays are equal, false otherwise. */ function equal(bytes memory _bytes, bytes memory _other) internal pure returns (bool) { return keccak256(_bytes) == keccak256(_other); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; /** * @custom:attribution https://github.com/hamdiallam/Solidity-RLP * @title RLPReader * @notice RLPReader is a library for parsing RLP-encoded byte arrays into Solidity types. Adapted * from Solidity-RLP (https://github.com/hamdiallam/Solidity-RLP) by Hamdi Allam with * various tweaks to improve readability. */ library RLPReader { /** * Custom pointer type to avoid confusion between pointers and uint256s. */ type MemoryPointer is uint256; /** * @notice RLP item types. * * @custom:value DATA_ITEM Represents an RLP data item (NOT a list). * @custom:value LIST_ITEM Represents an RLP list item. */ enum RLPItemType { DATA_ITEM, LIST_ITEM } /** * @notice Struct representing an RLP item. * * @custom:field length Length of the RLP item. * @custom:field ptr Pointer to the RLP item in memory. */ struct RLPItem { uint256 length; MemoryPointer ptr; } /** * @notice Max list length that this library will accept. */ uint256 internal constant MAX_LIST_LENGTH = 32; /** * @notice Converts bytes to a reference to memory position and length. * * @param _in Input bytes to convert. * * @return Output memory reference. */ function toRLPItem(bytes memory _in) internal pure returns (RLPItem memory) { // Empty arrays are not RLP items. require( _in.length > 0, "RLPReader: length of an RLP item must be greater than zero to be decodable" ); MemoryPointer ptr; assembly { ptr := add(_in, 32) } return RLPItem({ length: _in.length, ptr: ptr }); } /** * @notice Reads an RLP list value into a list of RLP items. * * @param _in RLP list value. * * @return Decoded RLP list items. */ function readList(RLPItem memory _in) internal pure returns (RLPItem[] memory) { (uint256 listOffset, uint256 listLength, RLPItemType itemType) = _decodeLength(_in); require( itemType == RLPItemType.LIST_ITEM, "RLPReader: decoded item type for list is not a list item" ); require( listOffset + listLength == _in.length, "RLPReader: list item has an invalid data remainder" ); // Solidity in-memory arrays can't be increased in size, but *can* be decreased in size by // writing to the length. Since we can't know the number of RLP items without looping over // the entire input, we'd have to loop twice to accurately size this array. It's easier to // simply set a reasonable maximum list length and decrease the size before we finish. RLPItem[] memory out = new RLPItem[](MAX_LIST_LENGTH); uint256 itemCount = 0; uint256 offset = listOffset; while (offset < _in.length) { (uint256 itemOffset, uint256 itemLength, ) = _decodeLength( RLPItem({ length: _in.length - offset, ptr: MemoryPointer.wrap(MemoryPointer.unwrap(_in.ptr) + offset) }) ); // We don't need to check itemCount < out.length explicitly because Solidity already // handles this check on our behalf, we'd just be wasting gas. out[itemCount] = RLPItem({ length: itemLength + itemOffset, ptr: MemoryPointer.wrap(MemoryPointer.unwrap(_in.ptr) + offset) }); itemCount += 1; offset += itemOffset + itemLength; } // Decrease the array size to match the actual item count. assembly { mstore(out, itemCount) } return out; } /** * @notice Reads an RLP list value into a list of RLP items. * * @param _in RLP list value. * * @return Decoded RLP list items. */ function readList(bytes memory _in) internal pure returns (RLPItem[] memory) { return readList(toRLPItem(_in)); } /** * @notice Reads an RLP bytes value into bytes. * * @param _in RLP bytes value. * * @return Decoded bytes. */ function readBytes(RLPItem memory _in) internal pure returns (bytes memory) { (uint256 itemOffset, uint256 itemLength, RLPItemType itemType) = _decodeLength(_in); require( itemType == RLPItemType.DATA_ITEM, "RLPReader: decoded item type for bytes is not a data item" ); require( _in.length == itemOffset + itemLength, "RLPReader: bytes value contains an invalid remainder" ); return _copy(_in.ptr, itemOffset, itemLength); } /** * @notice Reads an RLP bytes value into bytes. * * @param _in RLP bytes value. * * @return Decoded bytes. */ function readBytes(bytes memory _in) internal pure returns (bytes memory) { return readBytes(toRLPItem(_in)); } /** * @notice Reads the raw bytes of an RLP item. * * @param _in RLP item to read. * * @return Raw RLP bytes. */ function readRawBytes(RLPItem memory _in) internal pure returns (bytes memory) { return _copy(_in.ptr, 0, _in.length); } /** * @notice Decodes the length of an RLP item. * * @param _in RLP item to decode. * * @return Offset of the encoded data. * @return Length of the encoded data. * @return RLP item type (LIST_ITEM or DATA_ITEM). */ function _decodeLength(RLPItem memory _in) private pure returns ( uint256, uint256, RLPItemType ) { // Short-circuit if there's nothing to decode, note that we perform this check when // the user creates an RLP item via toRLPItem, but it's always possible for them to bypass // that function and create an RLP item directly. So we need to check this anyway. require( _in.length > 0, "RLPReader: length of an RLP item must be greater than zero to be decodable" ); MemoryPointer ptr = _in.ptr; uint256 prefix; assembly { prefix := byte(0, mload(ptr)) } if (prefix <= 0x7f) { // Single byte. return (0, 1, RLPItemType.DATA_ITEM); } else if (prefix <= 0xb7) { // Short string. // slither-disable-next-line variable-scope uint256 strLen = prefix - 0x80; require( _in.length > strLen, "RLPReader: length of content must be greater than string length (short string)" ); bytes1 firstByteOfContent; assembly { firstByteOfContent := and(mload(add(ptr, 1)), shl(248, 0xff)) } require( strLen != 1 || firstByteOfContent >= 0x80, "RLPReader: invalid prefix, single byte < 0x80 are not prefixed (short string)" ); return (1, strLen, RLPItemType.DATA_ITEM); } else if (prefix <= 0xbf) { // Long string. uint256 lenOfStrLen = prefix - 0xb7; require( _in.length > lenOfStrLen, "RLPReader: length of content must be > than length of string length (long string)" ); bytes1 firstByteOfContent; assembly { firstByteOfContent := and(mload(add(ptr, 1)), shl(248, 0xff)) } require( firstByteOfContent != 0x00, "RLPReader: length of content must not have any leading zeros (long string)" ); uint256 strLen; assembly { strLen := shr(sub(256, mul(8, lenOfStrLen)), mload(add(ptr, 1))) } require( strLen > 55, "RLPReader: length of content must be greater than 55 bytes (long string)" ); require( _in.length > lenOfStrLen + strLen, "RLPReader: length of content must be greater than total length (long string)" ); return (1 + lenOfStrLen, strLen, RLPItemType.DATA_ITEM); } else if (prefix <= 0xf7) { // Short list. // slither-disable-next-line variable-scope uint256 listLen = prefix - 0xc0; require( _in.length > listLen, "RLPReader: length of content must be greater than list length (short list)" ); return (1, listLen, RLPItemType.LIST_ITEM); } else { // Long list. uint256 lenOfListLen = prefix - 0xf7; require( _in.length > lenOfListLen, "RLPReader: length of content must be > than length of list length (long list)" ); bytes1 firstByteOfContent; assembly { firstByteOfContent := and(mload(add(ptr, 1)), shl(248, 0xff)) } require( firstByteOfContent != 0x00, "RLPReader: length of content must not have any leading zeros (long list)" ); uint256 listLen; assembly { listLen := shr(sub(256, mul(8, lenOfListLen)), mload(add(ptr, 1))) } require( listLen > 55, "RLPReader: length of content must be greater than 55 bytes (long list)" ); require( _in.length > lenOfListLen + listLen, "RLPReader: length of content must be greater than total length (long list)" ); return (1 + lenOfListLen, listLen, RLPItemType.LIST_ITEM); } } /** * @notice Copies the bytes from a memory location. * * @param _src Pointer to the location to read from. * @param _offset Offset to start reading from. * @param _length Number of bytes to read. * * @return Copied bytes. */ function _copy( MemoryPointer _src, uint256 _offset, uint256 _length ) private pure returns (bytes memory) { bytes memory out = new bytes(_length); if (_length == 0) { return out; } // Mostly based on Solidity's copy_memory_to_memory: // solhint-disable max-line-length // https://github.com/ethereum/solidity/blob/34dd30d71b4da730488be72ff6af7083cf2a91f6/libsolidity/codegen/YulUtilFunctions.cpp#L102-L114 uint256 src = MemoryPointer.unwrap(_src) + _offset; assembly { let dest := add(out, 32) let i := 0 for { } lt(i, _length) { i := add(i, 32) } { mstore(add(dest, i), mload(add(src, i))) } if gt(i, _length) { mstore(add(dest, _length), 0) } } return out; } /** * Reads an RLP bytes32 value into a bytes32. * @param _in RLP bytes32 value. * @return Decoded bytes32. */ function readBytes32(RLPItem memory _in) internal pure returns (bytes32) { require(_in.length <= 33, "Invalid RLP bytes32 value."); (uint256 itemOffset, uint256 itemLength, RLPItemType itemType) = _decodeLength(_in); require(itemType == RLPItemType.DATA_ITEM, "Invalid RLP bytes32 value."); uint256 ptr = MemoryPointer.unwrap(_in.ptr) + itemOffset; bytes32 out; assembly { out := mload(ptr) // Shift the bytes over to match the item size. if lt(itemLength, 32) { out := div(out, exp(256, sub(32, itemLength))) } } return out; } /** * Reads an RLP uint256 value into a uint256. * @param _in RLP uint256 value. * @return Decoded uint256. */ function readUint256(RLPItem memory _in) internal pure returns (uint256) { return uint256(readBytes32(_in)); } /** * Reads an RLP address value into a address. * @param _in RLP address value. * @return Decoded address. */ function readAddress(RLPItem memory _in) internal pure returns (address) { if (_in.length == 1) { return address(0); } require(_in.length == 21, "Invalid RLP address value."); return address(uint160(readUint256(_in))); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @custom:attribution https://github.com/bakaoh/solidity-rlp-encode * @title RLPWriter * @author RLPWriter is a library for encoding Solidity types to RLP bytes. Adapted from Bakaoh's * RLPEncode library (https://github.com/bakaoh/solidity-rlp-encode) with minor * modifications to improve legibility. */ library RLPWriter { /** * @notice RLP encodes a byte string. * * @param _in The byte string to encode. * * @return The RLP encoded string in bytes. */ function writeBytes(bytes memory _in) internal pure returns (bytes memory) { bytes memory encoded; if (_in.length == 1 && uint8(_in[0]) < 128) { encoded = _in; } else { encoded = abi.encodePacked(_writeLength(_in.length, 128), _in); } return encoded; } /** * @notice RLP encodes a list of RLP encoded byte byte strings. * * @param _in The list of RLP encoded byte strings. * * @return The RLP encoded list of items in bytes. */ function writeList(bytes[] memory _in) internal pure returns (bytes memory) { bytes memory list = _flatten(_in); return abi.encodePacked(_writeLength(list.length, 192), list); } /** * @notice RLP encodes a string. * * @param _in The string to encode. * * @return The RLP encoded string in bytes. */ function writeString(string memory _in) internal pure returns (bytes memory) { return writeBytes(bytes(_in)); } /** * @notice RLP encodes an address. * * @param _in The address to encode. * * @return The RLP encoded address in bytes. */ function writeAddress(address _in) internal pure returns (bytes memory) { return writeBytes(abi.encodePacked(_in)); } /** * @notice RLP encodes a uint. * * @param _in The uint256 to encode. * * @return The RLP encoded uint256 in bytes. */ function writeUint(uint256 _in) internal pure returns (bytes memory) { return writeBytes(_toBinary(_in)); } /** * @notice RLP encodes a bool. * * @param _in The bool to encode. * * @return The RLP encoded bool in bytes. */ function writeBool(bool _in) internal pure returns (bytes memory) { bytes memory encoded = new bytes(1); encoded[0] = (_in ? bytes1(0x01) : bytes1(0x80)); return encoded; } /** * @notice Encode the first byte and then the `len` in binary form if `length` is more than 55. * * @param _len The length of the string or the payload. * @param _offset 128 if item is string, 192 if item is list. * * @return RLP encoded bytes. */ function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory) { bytes memory encoded; if (_len < 56) { encoded = new bytes(1); encoded[0] = bytes1(uint8(_len) + uint8(_offset)); } else { uint256 lenLen; uint256 i = 1; while (_len / i != 0) { lenLen++; i *= 256; } encoded = new bytes(lenLen + 1); encoded[0] = bytes1(uint8(lenLen) + uint8(_offset) + 55); for (i = 1; i <= lenLen; i++) { encoded[i] = bytes1(uint8((_len / (256**(lenLen - i))) % 256)); } } return encoded; } /** * @notice Encode integer in big endian binary form with no leading zeroes. * * @param _x The integer to encode. * * @return RLP encoded bytes. */ function _toBinary(uint256 _x) private pure returns (bytes memory) { bytes memory b = abi.encodePacked(_x); uint256 i = 0; for (; i < 32; i++) { if (b[i] != 0) { break; } } bytes memory res = new bytes(32 - i); for (uint256 j = 0; j < res.length; j++) { res[j] = b[i++]; } return res; } /** * @custom:attribution https://github.com/Arachnid/solidity-stringutils * @notice Copies a piece of memory to another location. * * @param _dest Destination location. * @param _src Source location. * @param _len Length of memory to copy. */ function _memcpy( uint256 _dest, uint256 _src, uint256 _len ) private pure { uint256 dest = _dest; uint256 src = _src; uint256 len = _len; for (; len >= 32; len -= 32) { assembly { mstore(dest, mload(src)) } dest += 32; src += 32; } uint256 mask; unchecked { mask = 256**(32 - len) - 1; } assembly { let srcpart := and(mload(src), not(mask)) let destpart := and(mload(dest), mask) mstore(dest, or(destpart, srcpart)) } } /** * @custom:attribution https://github.com/sammayo/solidity-rlp-encoder * @notice Flattens a list of byte strings into one byte string. * * @param _list List of byte strings to flatten. * * @return The flattened byte string. */ function _flatten(bytes[] memory _list) private pure returns (bytes memory) { if (_list.length == 0) { return new bytes(0); } uint256 len; uint256 i = 0; for (; i < _list.length; i++) { len += _list[i].length; } bytes memory flattened = new bytes(len); uint256 flattenedPtr; assembly { flattenedPtr := add(flattened, 0x20) } for (i = 0; i < _list.length; i++) { bytes memory item = _list[i]; uint256 listPtr; assembly { listPtr := add(item, 0x20) } _memcpy(flattenedPtr, listPtr, item.length); flattenedPtr += _list[i].length; } return flattened; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { Bytes } from "../Bytes.sol"; import { RLPReader } from "../rlp/RLPReader.sol"; /** * @title MerkleTrie * @notice MerkleTrie is a small library for verifying standard Ethereum Merkle-Patricia trie * inclusion proofs. By default, this library assumes a hexary trie. One can change the * trie radix constant to support other trie radixes. */ library MerkleTrie { /** * @notice Struct representing a node in the trie. * * @custom:field encoded The RLP-encoded node. * @custom:field decoded The RLP-decoded node. */ struct TrieNode { bytes encoded; RLPReader.RLPItem[] decoded; } /** * @notice Determines the number of elements per branch node. */ uint256 internal constant TREE_RADIX = 16; /** * @notice Branch nodes have TREE_RADIX elements and one value element. */ uint256 internal constant BRANCH_NODE_LENGTH = TREE_RADIX + 1; /** * @notice Leaf nodes and extension nodes have two elements, a `path` and a `value`. */ uint256 internal constant LEAF_OR_EXTENSION_NODE_LENGTH = 2; /** * @notice Prefix for even-nibbled extension node paths. */ uint8 internal constant PREFIX_EXTENSION_EVEN = 0; /** * @notice Prefix for odd-nibbled extension node paths. */ uint8 internal constant PREFIX_EXTENSION_ODD = 1; /** * @notice Prefix for even-nibbled leaf node paths. */ uint8 internal constant PREFIX_LEAF_EVEN = 2; /** * @notice Prefix for odd-nibbled leaf node paths. */ uint8 internal constant PREFIX_LEAF_ODD = 3; /** * @notice Verifies a proof that a given key/value pair is present in the trie. * * @param _key Key of the node to search for, as a hex string. * @param _value Value of the node to search for, as a hex string. * @param _proof Merkle trie inclusion proof for the desired node. Unlike traditional Merkle * trees, this proof is executed top-down and consists of a list of RLP-encoded * nodes that make a path down to the target node. * @param _root Known root of the Merkle trie. Used to verify that the included proof is * correctly constructed. * * @return Whether or not the proof is valid. */ function verifyInclusionProof( bytes memory _key, bytes memory _value, bytes[] memory _proof, bytes32 _root ) internal pure returns (bool) { return Bytes.equal(_value, get(_key, _proof, _root)); } /** * @notice Retrieves the value associated with a given key. * * @param _key Key to search for, as hex bytes. * @param _proof Merkle trie inclusion proof for the key. * @param _root Known root of the Merkle trie. * * @return Value of the key if it exists. */ function get( bytes memory _key, bytes[] memory _proof, bytes32 _root ) internal pure returns (bytes memory) { require(_key.length > 0, "MerkleTrie: empty key"); TrieNode[] memory proof = _parseProof(_proof); bytes memory key = Bytes.toNibbles(_key); bytes memory currentNodeID = abi.encodePacked(_root); uint256 currentKeyIndex = 0; // Proof is top-down, so we start at the first element (root). for (uint256 i = 0; i < proof.length; i++) { TrieNode memory currentNode = proof[i]; // Key index should never exceed total key length or we'll be out of bounds. require( currentKeyIndex <= key.length, "MerkleTrie: key index exceeds total key length" ); if (currentKeyIndex == 0) { // First proof element is always the root node. require( Bytes.equal(abi.encodePacked(keccak256(currentNode.encoded)), currentNodeID), "MerkleTrie: invalid root hash" ); } else if (currentNode.encoded.length >= 32) { // Nodes 32 bytes or larger are hashed inside branch nodes. require( Bytes.equal(abi.encodePacked(keccak256(currentNode.encoded)), currentNodeID), "MerkleTrie: invalid large internal hash" ); } else { // Nodes smaller than 32 bytes aren't hashed. require( Bytes.equal(currentNode.encoded, currentNodeID), "MerkleTrie: invalid internal node hash" ); } if (currentNode.decoded.length == BRANCH_NODE_LENGTH) { if (currentKeyIndex == key.length) { // Value is the last element of the decoded list (for branch nodes). There's // some ambiguity in the Merkle trie specification because bytes(0) is a // valid value to place into the trie, but for branch nodes bytes(0) can exist // even when the value wasn't explicitly placed there. Geth treats a value of // bytes(0) as "key does not exist" and so we do the same. bytes memory value = RLPReader.readBytes(currentNode.decoded[TREE_RADIX]); require( value.length > 0, "MerkleTrie: value length must be greater than zero (branch)" ); // Extra proof elements are not allowed. require( i == proof.length - 1, "MerkleTrie: value node must be last node in proof (branch)" ); return value; } else { // We're not at the end of the key yet. // Figure out what the next node ID should be and continue. uint8 branchKey = uint8(key[currentKeyIndex]); RLPReader.RLPItem memory nextNode = currentNode.decoded[branchKey]; currentNodeID = _getNodeID(nextNode); currentKeyIndex += 1; } } else if (currentNode.decoded.length == LEAF_OR_EXTENSION_NODE_LENGTH) { bytes memory path = _getNodePath(currentNode); uint8 prefix = uint8(path[0]); uint8 offset = 2 - (prefix % 2); bytes memory pathRemainder = Bytes.slice(path, offset); bytes memory keyRemainder = Bytes.slice(key, currentKeyIndex); uint256 sharedNibbleLength = _getSharedNibbleLength(pathRemainder, keyRemainder); // Whether this is a leaf node or an extension node, the path remainder MUST be a // prefix of the key remainder (or be equal to the key remainder) or the proof is // considered invalid. require( pathRemainder.length == sharedNibbleLength, "MerkleTrie: path remainder must share all nibbles with key" ); if (prefix == PREFIX_LEAF_EVEN || prefix == PREFIX_LEAF_ODD) { // Prefix of 2 or 3 means this is a leaf node. For the leaf node to be valid, // the key remainder must be exactly equal to the path remainder. We already // did the necessary byte comparison, so it's more efficient here to check that // the key remainder length equals the shared nibble length, which implies // equality with the path remainder (since we already did the same check with // the path remainder and the shared nibble length). require( keyRemainder.length == sharedNibbleLength, "MerkleTrie: key remainder must be identical to path remainder" ); // Our Merkle Trie is designed specifically for the purposes of the Ethereum // state trie. Empty values are not allowed in the state trie, so we can safely // say that if the value is empty, the key should not exist and the proof is // invalid. bytes memory value = RLPReader.readBytes(currentNode.decoded[1]); require( value.length > 0, "MerkleTrie: value length must be greater than zero (leaf)" ); // Extra proof elements are not allowed. require( i == proof.length - 1, "MerkleTrie: value node must be last node in proof (leaf)" ); return value; } else if (prefix == PREFIX_EXTENSION_EVEN || prefix == PREFIX_EXTENSION_ODD) { // Prefix of 0 or 1 means this is an extension node. We move onto the next node // in the proof and increment the key index by the length of the path remainder // which is equal to the shared nibble length. currentNodeID = _getNodeID(currentNode.decoded[1]); currentKeyIndex += sharedNibbleLength; } else { revert("MerkleTrie: received a node with an unknown prefix"); } } else { revert("MerkleTrie: received an unparseable node"); } } revert("MerkleTrie: ran out of proof elements"); } /** * @notice Parses an array of proof elements into a new array that contains both the original * encoded element and the RLP-decoded element. * * @param _proof Array of proof elements to parse. * * @return Proof parsed into easily accessible structs. */ function _parseProof(bytes[] memory _proof) private pure returns (TrieNode[] memory) { uint256 length = _proof.length; TrieNode[] memory proof = new TrieNode[](length); for (uint256 i = 0; i < length; ) { proof[i] = TrieNode({ encoded: _proof[i], decoded: RLPReader.readList(_proof[i]) }); unchecked { ++i; } } return proof; } /** * @notice Picks out the ID for a node. Node ID is referred to as the "hash" within the * specification, but nodes < 32 bytes are not actually hashed. * * @param _node Node to pull an ID for. * * @return ID for the node, depending on the size of its contents. */ function _getNodeID(RLPReader.RLPItem memory _node) private pure returns (bytes memory) { return _node.length < 32 ? RLPReader.readRawBytes(_node) : RLPReader.readBytes(_node); } /** * @notice Gets the path for a leaf or extension node. * * @param _node Node to get a path for. * * @return Node path, converted to an array of nibbles. */ function _getNodePath(TrieNode memory _node) private pure returns (bytes memory) { return Bytes.toNibbles(RLPReader.readBytes(_node.decoded[0])); } /** * @notice Utility; determines the number of nibbles shared between two nibble arrays. * * @param _a First nibble array. * @param _b Second nibble array. * * @return Number of shared nibbles. */ function _getSharedNibbleLength(bytes memory _a, bytes memory _b) private pure returns (uint256) { uint256 shared; uint256 max = (_a.length < _b.length) ? _a.length : _b.length; for (; shared < max && _a[shared] == _b[shared]; ) { unchecked { ++shared; } } return shared; } }
pragma solidity 0.8.16; import {UUPSUpgradeable} from "openzeppelin-contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import {OwnableUpgradeable} from "openzeppelin-contracts-upgradeable/access/OwnableUpgradeable.sol"; import {Bytes32} from "src/libraries/Typecast.sol"; import {MessageEncoding} from "src/libraries/MessageEncoding.sol"; import {ITelepathyRouter, Message} from "./interfaces/ITelepathy.sol"; import {TelepathyAccess} from "./TelepathyAccess.sol"; import {TelepathyStorage} from "./TelepathyStorage.sol"; /// @title Source Arbitrary Message Bridge /// @author Succinct Labs /// @notice This contract is the entrypoint for sending messages to other chains. contract SourceAMB is TelepathyStorage, ITelepathyRouter { /// @notice Modifier to require that sending is enabled. modifier isSendingEnabled() { require(sendingEnabled, "Sending is disabled"); _; } /// @notice Sends a message to a target chain. /// @param recipientChainId The chain id that specifies the target chain. /// @param recipientAddress The contract address that will be called on the target chain. /// @param data The data passed to the contract on the other chain /// @return bytes32 A unique identifier for a message. function send(uint32 recipientChainId, bytes32 recipientAddress, bytes calldata data) external isSendingEnabled returns (bytes32) { require(recipientChainId != block.chainid, "Cannot send to same chain"); (bytes memory message, bytes32 messageRoot) = _getMessageAndRoot(recipientChainId, recipientAddress, data); emit SentMessage(nonce++, messageRoot, message); return messageRoot; } function send(uint32 recipientChainId, address recipientAddress, bytes calldata data) external isSendingEnabled returns (bytes32) { require(recipientChainId != block.chainid, "Cannot send to same chain"); (bytes memory message, bytes32 messageRoot) = _getMessageAndRoot(recipientChainId, Bytes32.fromAddress(recipientAddress), data); emit SentMessage(nonce++, messageRoot, message); return messageRoot; } /// @notice Sends a message to a target chain. /// @notice This method is more expensive than the `send` method as it requires adding to /// contract storage. Use `send` when interacting with Telepathy to save gas. /// @param recipientChainId The chain id that specifies the target chain. /// @param recipientAddress The contract address that will be called on the target chain. /// @param data The data passed to the contract on the other chain /// @return bytes32 A unique identifier for a message. function sendViaStorage(uint32 recipientChainId, bytes32 recipientAddress, bytes calldata data) external isSendingEnabled returns (bytes32) { require(recipientChainId != block.chainid, "Cannot send to same chain"); (bytes memory message, bytes32 messageRoot) = _getMessageAndRoot(recipientChainId, recipientAddress, data); messages[nonce] = messageRoot; emit SentMessage(nonce++, messageRoot, message); return messageRoot; } function sendViaStorage(uint32 recipientChainId, address recipientAddress, bytes calldata data) external isSendingEnabled returns (bytes32) { require(recipientChainId != block.chainid, "Cannot send to same chain"); (bytes memory message, bytes32 messageRoot) = _getMessageAndRoot(recipientChainId, Bytes32.fromAddress(recipientAddress), data); messages[nonce] = messageRoot; emit SentMessage(nonce++, messageRoot, message); return messageRoot; } /// @notice Gets the message and message root from the user-provided arguments to `send` /// @param recipientChainId The chain id that specifies the target chain. /// @param recipientAddress The contract address that will be called on the target chain. /// @param data The calldata used when calling the contract on the target chain. /// @return messageBytes The message encoded as bytes, used in SentMessage event. /// @return messageRoot The hash of messageBytes, used as a unique identifier for a message. function _getMessageAndRoot( uint32 recipientChainId, bytes32 recipientAddress, bytes calldata data ) internal view returns (bytes memory messageBytes, bytes32 messageRoot) { messageBytes = MessageEncoding.encode( version, nonce, uint32(block.chainid), msg.sender, recipientChainId, recipientAddress, data ); messageRoot = keccak256(messageBytes); } }
pragma solidity 0.8.16; import {ReentrancyGuardUpgradeable} from "openzeppelin-contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import {SSZ} from "src/libraries/SimpleSerialize.sol"; import {StorageProof, EventProof} from "src/libraries/StateProofHelper.sol"; import {Address} from "src/libraries/Typecast.sol"; import {MessageEncoding} from "src/libraries/MessageEncoding.sol"; import {TelepathyStorage} from "./TelepathyStorage.sol"; import { ITelepathyHandler, ITelepathyReceiver, Message, MessageStatus } from "./interfaces/ITelepathy.sol"; /// @title Target Arbitrary Message Bridge /// @author Succinct Labs /// @notice Executes messages sent from the source chain on the target chain. contract TargetAMB is TelepathyStorage, ReentrancyGuardUpgradeable, ITelepathyReceiver { /// @notice The minimum delay for using any information from the light client. uint256 public constant MIN_LIGHT_CLIENT_DELAY = 2 minutes; /// @notice The ITelepathyBroadcaster SentMessage event signature used in `executeMessageFromLog`. bytes32 internal constant SENT_MESSAGE_EVENT_SIG = keccak256("SentMessage(uint64,bytes32,bytes)"); /// @notice The topic index of the message root in the SourceAMB SentMessage event. /// @dev Because topic[0] is the hash of the event signature (`SENT_MESSAGE_EVENT_SIG` above), /// the topic index of msgHash is 2. uint256 internal constant MSG_HASH_TOPIC_IDX = 2; /// @notice The index of the `messages` mapping in TelepathyStorage.sol. /// @dev We need this when calling `executeMessage` via storage proofs, as it is used in /// getting the slot key. uint256 internal constant MESSAGES_MAPPING_STORAGE_INDEX = 1; /// @notice Gets the length of the sourceChainIds array. /// @return The length of the sourceChainIds array. function sourceChainIdsLength() external view returns (uint256) { return sourceChainIds.length; } /// @notice Executes a message given a storage proof. /// @param slot Specifies which execution state root should be read from the light client. /// @param messageBytes The message we want to execute provided as bytes. /// @param accountProof Used to prove the broadcaster's state root. /// @param storageProof Used to prove the existence of the message root inside the broadcaster. function executeMessage( uint64 slot, bytes calldata messageBytes, bytes[] calldata accountProof, bytes[] calldata storageProof ) external nonReentrant { (Message memory message, bytes32 messageRoot) = _checkPreconditions(messageBytes); requireLightClientConsistency(message.sourceChainId); requireNotFrozen(message.sourceChainId); { requireLightClientDelay(slot, message.sourceChainId); bytes32 storageRoot; bytes32 cacheKey = keccak256( abi.encodePacked(message.sourceChainId, slot, broadcasters[message.sourceChainId]) ); // If the cache is empty for the cacheKey, then we get the // storageRoot using the provided accountProof. if (storageRootCache[cacheKey] == 0) { bytes32 executionStateRoot = lightClients[message.sourceChainId].executionStateRoots(slot); require(executionStateRoot != 0, "Execution State Root is not set"); storageRoot = StorageProof.getStorageRoot( accountProof, broadcasters[message.sourceChainId], executionStateRoot ); storageRootCache[cacheKey] = storageRoot; } else { storageRoot = storageRootCache[cacheKey]; } bytes32 slotKey = keccak256( abi.encode(keccak256(abi.encode(message.nonce, MESSAGES_MAPPING_STORAGE_INDEX))) ); uint256 slotValue = StorageProof.getStorageValue(slotKey, storageRoot, storageProof); if (bytes32(slotValue) != messageRoot) { revert("Invalid message hash."); } } _executeMessage(message, messageRoot, messageBytes); } /// @notice Executes a message given an event proof. /// @param srcSlotTxSlotPack The slot where we want to read the header from and the slot where /// the tx executed, packed as two uint64s. /// @param messageBytes The message we want to execute provided as bytes. /// @param receiptsRootProof A merkle proof proving the receiptsRoot in the block header. /// @param receiptsRoot The receipts root which contains our "SentMessage" event. /// @param txIndexRLPEncoded The index of our transaction inside the block RLP encoded. /// @param logIndex The index of the event in our transaction. function executeMessageFromLog( bytes calldata srcSlotTxSlotPack, bytes calldata messageBytes, bytes32[] calldata receiptsRootProof, bytes32 receiptsRoot, bytes[] calldata receiptProof, bytes memory txIndexRLPEncoded, uint256 logIndex ) external nonReentrant { // Verify receiptsRoot against header from light client (Message memory message, bytes32 messageRoot) = _checkPreconditions(messageBytes); requireLightClientConsistency(message.sourceChainId); requireNotFrozen(message.sourceChainId); { (uint64 srcSlot, uint64 txSlot) = abi.decode(srcSlotTxSlotPack, (uint64, uint64)); requireLightClientDelay(srcSlot, message.sourceChainId); bytes32 headerRoot = lightClients[message.sourceChainId].headers(srcSlot); require(headerRoot != bytes32(0), "HeaderRoot is missing"); bool isValid = SSZ.verifyReceiptsRoot(receiptsRoot, receiptsRootProof, headerRoot, srcSlot, txSlot); require(isValid, "Invalid receipts root proof"); } { // TODO maybe we can save calldata by passing in the txIndex as a uint and rlp encode it // to derive txIndexRLPEncoded instead of passing in `bytes memory txIndexRLPEncoded` bytes32 receiptMessageRoot = bytes32( EventProof.getEventTopic( receiptProof, receiptsRoot, txIndexRLPEncoded, logIndex, broadcasters[message.sourceChainId], SENT_MESSAGE_EVENT_SIG, MSG_HASH_TOPIC_IDX ) ); require(receiptMessageRoot == messageRoot, "Invalid message hash."); } _executeMessage(message, messageRoot, messageBytes); } /// @notice Checks that the light client for a given chainId is consistent. function requireLightClientConsistency(uint32 chainId) internal view { require(address(lightClients[chainId]) != address(0), "Light client is not set."); require(lightClients[chainId].consistent(), "Light client is inconsistent."); } /// @notice Checks that the chainId is not frozen. function requireNotFrozen(uint32 chainId) internal view { require(!frozen[chainId], "Contract is frozen."); } /// @notice Checks that the light client delay is adequate. function requireLightClientDelay(uint64 slot, uint32 chainId) internal view { require(address(lightClients[chainId]) != address(0), "Light client is not set."); require(lightClients[chainId].timestamps(slot) != 0, "Timestamp is not set for slot."); uint256 elapsedTime = block.timestamp - lightClients[chainId].timestamps(slot); require(elapsedTime >= MIN_LIGHT_CLIENT_DELAY, "Must wait longer to use this slot."); } /// @notice Decodes the message from messageBytes and checks conditions before message execution /// @param messageBytes The message we want to execute provided as bytes. function _checkPreconditions(bytes calldata messageBytes) internal view returns (Message memory, bytes32) { Message memory message = MessageEncoding.decode(messageBytes); bytes32 messageRoot = keccak256(messageBytes); if (messageStatus[messageRoot] != MessageStatus.NOT_EXECUTED) { revert("Message already executed."); } else if (message.recipientChainId != block.chainid) { revert("Wrong chain."); } else if (message.version != version) { revert("Wrong version."); } else if ( address(lightClients[message.sourceChainId]) == address(0) || broadcasters[message.sourceChainId] == address(0) ) { revert("Light client or broadcaster for source chain is not set"); } return (message, messageRoot); } /// @notice Executes a message and updates storage with status and emits an event. /// @dev Assumes that the message is valid and has not been already executed. /// @dev Assumes that message, messageRoot and messageBytes have already been validated. /// @param message The message we want to execute. /// @param messageRoot The message root of the message. /// @param messageBytes The message we want to execute provided as bytes for use in the event. function _executeMessage(Message memory message, bytes32 messageRoot, bytes memory messageBytes) internal { bool status; bytes memory data; { bytes memory receiveCall = abi.encodeWithSelector( ITelepathyHandler.handleTelepathy.selector, message.sourceChainId, message.senderAddress, message.data ); address recipient = Address.fromBytes32(message.recipientAddress); (status, data) = recipient.call(receiveCall); } // Unfortunately, there are some edge cases where a call may have a successful status but // not have actually called the handler. Thus, we enforce that the handler must return // a magic constant that we can check here. To avoid stack underflow / decoding errors, we // only decode the returned bytes if one EVM word was returned by the call. bool implementsHandler = false; if (data.length == 32) { (bytes4 magic) = abi.decode(data, (bytes4)); implementsHandler = magic == ITelepathyHandler.handleTelepathy.selector; } if (status && implementsHandler) { messageStatus[messageRoot] = MessageStatus.EXECUTION_SUCCEEDED; } else { messageStatus[messageRoot] = MessageStatus.EXECUTION_FAILED; } emit ExecutedMessage( message.sourceChainId, message.nonce, messageRoot, messageBytes, status ); } }
pragma solidity 0.8.16; import {AccessControlUpgradeable} from "openzeppelin-contracts-upgradeable/access/AccessControlUpgradeable.sol"; import {ILightClient} from "src/lightclient/interfaces/ILightClient.sol"; import {TelepathyStorage} from "./TelepathyStorage.sol"; contract TelepathyAccess is TelepathyStorage, AccessControlUpgradeable { /// @notice Emitted when the sendingEnabled flag is changed. event SendingEnabled(bool enabled); /// @notice Emitted when freezeAll is called. event FreezeAll(); /// @notice Emitted when freeze is called. event Freeze(uint32 indexed chainId); /// @notice Emitted when unfreezeAll is called. event UnfreezeAll(); /// @notice Emitted when unfreeze is called. event Unfreeze(uint32 indexed chainId); /// @notice Emitted when setLightClientAndBroadcaster is called. event SetLightClientAndBroadcaster( uint32 indexed chainId, address lightClient, address broadcaster ); /// @notice Emitted when a new source chain is added. event SourceChainAdded(uint32 indexed chainId); /// @notice A random constant used to identify addresses with the permission of a 'guardian'. bytes32 public constant GUARDIAN_ROLE = keccak256("GUARDIAN_ROLE"); /// @notice A random constant used to identify addresses with the permission of a 'timelock'. bytes32 public constant TIMELOCK_ROLE = keccak256("TIMELOCK_ROLE"); modifier onlyAdmin() { require( hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "TelepathyRouter: only admin can call this function" ); _; } modifier onlyTimelock() { require( hasRole(TIMELOCK_ROLE, msg.sender), "TelepathyRouter: only timelock can call this function" ); _; } modifier onlyGuardian() { require( hasRole(GUARDIAN_ROLE, msg.sender), "TelepathyRouter: only guardian can call this function" ); _; } /// @notice Allows the owner to control whether sending is enabled or not. function setSendingEnabled(bool enabled) external onlyGuardian { sendingEnabled = enabled; emit SendingEnabled(enabled); } /// @notice Freezes messages from all chains. /// @dev This is a safety mechanism to prevent the contract from being used after a security /// vulnerability is detected. function freezeAll() external onlyGuardian { for (uint32 i = 0; i < sourceChainIds.length; i++) { frozen[sourceChainIds[i]] = true; } emit FreezeAll(); } /// @notice Freezes messages from the specified chain. /// @dev This is a safety mechanism to prevent the contract from being used after a security /// vulnerability is detected. function freeze(uint32 chainId) external onlyGuardian { frozen[chainId] = true; emit Freeze(chainId); } /// @notice Unfreezes messages from the specified chain. /// @dev This is a safety mechanism to continue usage of the contract after a security /// vulnerability is patched. function unfreeze(uint32 chainId) external onlyGuardian { frozen[chainId] = false; emit Unfreeze(chainId); } /// @notice Unfreezes messages from all chains. /// @dev This is a safety mechanism to continue usage of the contract after a security /// vulnerability is patched. function unfreezeAll() external onlyGuardian { for (uint32 i = 0; i < sourceChainIds.length; i++) { frozen[sourceChainIds[i]] = false; } emit UnfreezeAll(); } /// @notice Sets the light client contract and broadcaster for a given chainId. /// @dev This is controlled by the timelock as it is a potentially dangerous method /// since both the light client and broadcaster address are critical in verifying /// that only valid sent messages are executed. function setLightClientAndBroadcaster(uint32 chainId, address lightclient, address broadcaster) external onlyTimelock { bool chainIdExists = false; for (uint256 i = 0; i < sourceChainIds.length; i++) { if (sourceChainIds[i] == chainId) { chainIdExists = true; break; } } if (!chainIdExists) { sourceChainIds.push(chainId); emit SourceChainAdded(chainId); } lightClients[chainId] = ILightClient(lightclient); broadcasters[chainId] = broadcaster; emit SetLightClientAndBroadcaster(chainId, lightclient, broadcaster); } }
pragma solidity 0.8.16; import {ILightClient} from "src/lightclient/interfaces/ILightClient.sol"; import {MessageStatus} from "./interfaces/ITelepathy.sol"; contract TelepathyStorage { /*////////////////////////////////////////////////////////////// BROADCASTER STORAGE //////////////////////////////////////////////////////////////*/ /// @notice Whether sending is enabled or not. bool public sendingEnabled; /// @notice Mapping between a nonce and a message root. mapping(uint64 => bytes32) public messages; /// @notice Keeps track of the next nonce to be used. uint64 public nonce; /*////////////////////////////////////////////////////////////// RECEIVER STORAGE //////////////////////////////////////////////////////////////*/ /// @notice All sourceChainIds. uint32[] public sourceChainIds; /// @notice Mapping between source chainId and the corresponding light client. mapping(uint32 => ILightClient) public lightClients; /// @notice Mapping between source chainId and the address of the Telepathy broadcaster on that chain. mapping(uint32 => address) public broadcasters; /// @notice Mapping between a source chainId and whether it's frozen. mapping(uint32 => bool) public frozen; /// @notice Mapping between a message root and its status. mapping(bytes32 => MessageStatus) public messageStatus; /*////////////////////////////////////////////////////////////// SHARED STORAGE //////////////////////////////////////////////////////////////*/ /// @notice Returns current contract version. uint8 public version; /*////////////////////////////////////////////////////////////// RECEIVER STORAGE V2 //////////////////////////////////////////////////////////////*/ /// @notice Storage root cache. mapping(bytes32 => bytes32) public storageRootCache; /// @dev This empty reserved space is put in place to allow future versions to add new variables /// without shifting down storage in the inheritance chain. /// See: https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#storage-gaps uint256[40] private __gap; }
pragma solidity ^0.8.0; enum MessageStatus { NOT_EXECUTED, EXECUTION_FAILED, EXECUTION_SUCCEEDED } struct Message { uint8 version; uint64 nonce; uint32 sourceChainId; address senderAddress; uint32 recipientChainId; bytes32 recipientAddress; bytes data; } interface ITelepathyRouter { event SentMessage(uint64 indexed nonce, bytes32 indexed msgHash, bytes message); function send(uint32 recipientChainId, bytes32 recipientAddress, bytes calldata data) external returns (bytes32); function send(uint32 recipientChainId, address recipientAddress, bytes calldata data) external returns (bytes32); function sendViaStorage(uint32 recipientChainId, bytes32 recipientAddress, bytes calldata data) external returns (bytes32); function sendViaStorage(uint32 recipientChainId, address recipientAddress, bytes calldata data) external returns (bytes32); } interface ITelepathyReceiver { event ExecutedMessage( uint32 indexed sourceChainId, uint64 indexed nonce, bytes32 indexed msgHash, bytes message, bool status ); function executeMessage( uint64 slot, bytes calldata message, bytes[] calldata accountProof, bytes[] calldata storageProof ) external; function executeMessageFromLog( bytes calldata srcSlotTxSlotPack, bytes calldata messageBytes, bytes32[] calldata receiptsRootProof, bytes32 receiptsRoot, bytes[] calldata receiptProof, // receipt proof against receipt root bytes memory txIndexRLPEncoded, uint256 logIndex ) external; } interface ITelepathyHandler { function handleTelepathy(uint32 _sourceChainId, address _senderAddress, bytes memory _data) external returns (bytes4); }
pragma solidity 0.8.16; import {Message} from "src/amb/interfaces/ITelepathy.sol"; // From here: https://stackoverflow.com/questions/74443594/how-to-slice-bytes-memory-in-solidity library BytesLib { function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; // Check length is 0. `iszero` return 1 for `true` and 0 for `false`. 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) // Calculate length mod 32 to handle slices that are not a multiple of 32 in size. let lengthmod := and(_length, 31) // tempBytes will have the following format in memory: <length><data> // When copying data we will offset the start forward to avoid allocating additional memory // Therefore part of the length area will be written, but this will be overwritten later anyways. // In case no offset is require, the start is set to the data region (0x20 from the tempBytes) // mc will be used to keep track where to copy the data to. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // Same logic as for mc is applied and additionally the start offset specified for the method is added let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { // increase `mc` and `cc` to read the next word from memory mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Copy the data from source (cc location) to the slice data (mc location) mstore(mc, mload(cc)) } // Store the length of the slice. This will overwrite any partial data that // was copied when having slices that are not a multiple of 32. mstore(tempBytes, _length) // update free-memory pointer // allocating the array padded to 32 bytes like the compiler does now // To set the used memory as a multiple of 32, add 31 to the actual memory usage (mc) // and remove the modulo 32 (the `and` with `not(31)`) 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) // update free-memory pointer // tempBytes uses 32 bytes in memory (even when empty) for the length. mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } } library MessageEncoding { function encode(Message memory message) internal pure returns (bytes memory data) { data = abi.encodePacked( message.version, message.nonce, message.sourceChainId, message.senderAddress, message.recipientChainId, message.recipientAddress, message.data ); } function encode( uint8 version, uint64 nonce, uint32 sourceChainId, address senderAddress, uint32 recipientChainId, bytes32 recipientAddress, bytes memory data ) internal pure returns (bytes memory) { return abi.encodePacked( version, nonce, sourceChainId, senderAddress, recipientChainId, recipientAddress, data ); } function decode(bytes memory data) internal pure returns (Message memory message) { uint8 version; uint64 nonce; // 64 / 8 = 8 uint32 sourceChainId; // 32 / 8 = 4 address senderAddress; // 20 bytes uint32 recipientChainId; // 4 bytes bytes32 recipientAddress; // 32 // 8 + 4 + 20 + 4 + 32 = 68 assembly { version := mload(add(data, 1)) nonce := mload(add(data, 9)) sourceChainId := mload(add(data, 13)) senderAddress := mload(add(data, 33)) recipientChainId := mload(add(data, 37)) recipientAddress := mload(add(data, 69)) } message.version = version; message.nonce = nonce; message.sourceChainId = sourceChainId; message.senderAddress = senderAddress; message.recipientChainId = recipientChainId; message.recipientAddress = recipientAddress; message.data = BytesLib.slice(data, 69, data.length - 69); } }
pragma solidity 0.8.16; struct BeaconBlockHeader { uint64 slot; uint64 proposerIndex; bytes32 parentRoot; bytes32 stateRoot; bytes32 bodyRoot; } library SSZ { uint256 internal constant HISTORICAL_ROOTS_LIMIT = 16777216; uint256 internal constant SLOTS_PER_HISTORICAL_ROOT = 8192; function toLittleEndian(uint256 v) internal pure returns (bytes32) { v = ((v & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8) | ((v & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8); v = ((v & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16) | ((v & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16); v = ((v & 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >> 32) | ((v & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32); v = ((v & 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >> 64) | ((v & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64); v = (v >> 128) | (v << 128); return bytes32(v); } function restoreMerkleRoot(bytes32 leaf, uint256 index, bytes32[] memory branch) internal pure returns (bytes32) { require(2 ** (branch.length + 1) > index); bytes32 value = leaf; uint256 i = 0; while (index != 1) { if (index % 2 == 1) { value = sha256(bytes.concat(branch[i], value)); } else { value = sha256(bytes.concat(value, branch[i])); } index /= 2; i++; } return value; } function isValidMerkleBranch(bytes32 leaf, uint256 index, bytes32[] memory branch, bytes32 root) internal pure returns (bool) { bytes32 restoredMerkleRoot = restoreMerkleRoot(leaf, index, branch); return root == restoredMerkleRoot; } function sszBeaconBlockHeader(BeaconBlockHeader memory header) internal pure returns (bytes32) { bytes32 left = sha256( bytes.concat( sha256( bytes.concat(toLittleEndian(header.slot), toLittleEndian(header.proposerIndex)) ), sha256(bytes.concat(header.parentRoot, header.stateRoot)) ) ); bytes32 right = sha256( bytes.concat( sha256(bytes.concat(header.bodyRoot, bytes32(0))), sha256(bytes.concat(bytes32(0), bytes32(0))) ) ); return sha256(bytes.concat(left, right)); } function computeDomain(bytes4 forkVersion, bytes32 genesisValidatorsRoot) internal pure returns (bytes32) { return bytes32(uint256(0x07 << 248)) | (sha256(abi.encode(forkVersion, genesisValidatorsRoot)) >> 32); } function verifyReceiptsRoot( bytes32 receiptsRoot, bytes32[] memory receiptsRootProof, bytes32 headerRoot, uint64 srcSlot, uint64 txSlot ) internal pure returns (bool) { uint256 index; if (srcSlot == txSlot) { index = 8 + 3; index = index * 2 ** 9 + 387; } else if (srcSlot - txSlot <= SLOTS_PER_HISTORICAL_ROOT) { index = 8 + 3; index = index * 2 ** 5 + 6; index = index * SLOTS_PER_HISTORICAL_ROOT + txSlot % SLOTS_PER_HISTORICAL_ROOT; index = index * 2 ** 9 + 387; } else if (txSlot < srcSlot) { index = 8 + 3; index = index * 2 ** 5 + 7; index = index * 2 + 0; index = index * HISTORICAL_ROOTS_LIMIT + txSlot / SLOTS_PER_HISTORICAL_ROOT; index = index * 2 + 1; index = index * SLOTS_PER_HISTORICAL_ROOT + txSlot % SLOTS_PER_HISTORICAL_ROOT; index = index * 2 ** 9 + 387; } else { revert("TrustlessAMB: invalid target slot"); } return isValidMerkleBranch(receiptsRoot, index, receiptsRootProof, headerRoot); } }
pragma solidity 0.8.16; import {RLPReader} from "@optimism-bedrock/rlp/RLPReader.sol"; import {RLPWriter} from "@optimism-bedrock/rlp/RLPWriter.sol"; import {MerkleTrie} from "@optimism-bedrock/trie/MerkleTrie.sol"; library StorageProof { using RLPReader for RLPReader.RLPItem; using RLPReader for bytes; function getStorageValue(bytes32 slotHash, bytes32 storageRoot, bytes[] memory _stateProof) internal pure returns (uint256) { bytes memory valueRlpBytes = MerkleTrie.get(abi.encodePacked(slotHash), _stateProof, storageRoot); require(valueRlpBytes.length > 0, "Storage value does not exist"); return valueRlpBytes.toRLPItem().readUint256(); } function getStorageRoot(bytes[] memory proof, address contractAddress, bytes32 stateRoot) internal pure returns (bytes32) { bytes32 addressHash = keccak256(abi.encodePacked(contractAddress)); bytes memory acctRlpBytes = MerkleTrie.get(abi.encodePacked(addressHash), proof, stateRoot); require(acctRlpBytes.length > 0, "Account does not exist"); RLPReader.RLPItem[] memory acctFields = acctRlpBytes.toRLPItem().readList(); require(acctFields.length == 4); return bytes32(acctFields[2].readUint256()); } } library EventProof { using RLPReader for RLPReader.RLPItem; using RLPReader for bytes; function getEventTopic( bytes[] memory proof, bytes32 receiptRoot, bytes memory key, uint256 logIndex, address claimedEmitter, bytes32 eventSignature, uint256 topicIndex ) internal pure returns (bytes32) { bytes memory value = MerkleTrie.get(key, proof, receiptRoot); bytes1 txTypeOrFirstByte = value[0]; // Currently, there are three possible transaction types on Ethereum. Receipts either come // in the form "TransactionType | ReceiptPayload" or "ReceiptPayload". The currently // supported set of transaction types are 0x01 and 0x02. In this case, we must truncate // the first byte to access the payload. To detect the other case, we can use the fact // that the first byte of a RLP-encoded list will always be greater than 0xc0. // Reference 1: https://eips.ethereum.org/EIPS/eip-2718 // Reference 2: https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp uint256 offset; if (txTypeOrFirstByte == 0x01 || txTypeOrFirstByte == 0x02) { offset = 1; } else if (txTypeOrFirstByte >= 0xc0) { offset = 0; } else { revert("Unsupported transaction type"); } // Truncate the first byte if eneded and get the RLP decoding of the receipt. uint256 ptr; assembly { ptr := add(value, 32) } RLPReader.RLPItem memory valueAsItem = RLPReader.RLPItem({ length: value.length - offset, ptr: RLPReader.MemoryPointer.wrap(ptr + offset) }); // The length of the receipt must be at least four, as the fourth entry contains events RLPReader.RLPItem[] memory valueAsList = valueAsItem.readList(); require(valueAsList.length == 4, "Invalid receipt length"); // Read the logs from the receipts and check that it is not ill-formed RLPReader.RLPItem[] memory logs = valueAsList[3].readList(); require(logIndex < logs.length, "Log index out of bounds"); RLPReader.RLPItem[] memory relevantLog = logs[logIndex].readList(); require(relevantLog.length == 3, "Log has incorrect number of fields"); // Validate that the correct contract emitted the event address contractAddress = relevantLog[0].readAddress(); require(contractAddress == claimedEmitter, "Event was not emitted by claimedEmitter"); RLPReader.RLPItem[] memory topics = relevantLog[1].readList(); // Validate that the correct event was emitted by checking the event signature require( bytes32(topics[0].readUint256()) == eventSignature, "Event signature does not match eventSignature" ); return topics[topicIndex].readBytes32(); } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity 0.8.16; library Address { function fromBytes32(bytes32 buffer) internal pure returns (address) { return address(uint160(uint256(buffer))); } } library Bytes32 { function fromAddress(address addr) internal pure returns (bytes32) { return bytes32(uint256(uint160(addr))); } }
pragma solidity ^0.8.0; interface ILightClient { function consistent() external view returns (bool); function head() external view returns (uint256); function headers(uint256 slot) external view returns (bytes32); function executionStateRoots(uint256 slot) external view returns (bytes32); function timestamps(uint256 slot) external view returns (uint256); }
{ "remappings": [ "@optimism-bedrock/=lib/optimism-bedrock-contracts/", "@uniswap/=lib/", "Solidity-RLP/=lib/Solidity-RLP/contracts/", "curve-merkle-oracle/=lib/curve-merkle-oracle/contracts/", "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/", "optimism-bedrock-contracts/=lib/optimism-bedrock-contracts/", "v3-core/=lib/v3-core/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"sourceChainId","type":"uint32"},{"indexed":true,"internalType":"uint64","name":"nonce","type":"uint64"},{"indexed":true,"internalType":"bytes32","name":"msgHash","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"ExecutedMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"chainId","type":"uint32"}],"name":"Freeze","type":"event"},{"anonymous":false,"inputs":[],"name":"FreezeAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","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":"bool","name":"enabled","type":"bool"}],"name":"SendingEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"nonce","type":"uint64"},{"indexed":true,"internalType":"bytes32","name":"msgHash","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"}],"name":"SentMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"chainId","type":"uint32"},{"indexed":false,"internalType":"address","name":"lightClient","type":"address"},{"indexed":false,"internalType":"address","name":"broadcaster","type":"address"}],"name":"SetLightClientAndBroadcaster","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"chainId","type":"uint32"}],"name":"SourceChainAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"chainId","type":"uint32"}],"name":"Unfreeze","type":"event"},{"anonymous":false,"inputs":[],"name":"UnfreezeAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GUARDIAN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_LIGHT_CLIENT_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TIMELOCK_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"broadcasters","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"slot","type":"uint64"},{"internalType":"bytes","name":"messageBytes","type":"bytes"},{"internalType":"bytes[]","name":"accountProof","type":"bytes[]"},{"internalType":"bytes[]","name":"storageProof","type":"bytes[]"}],"name":"executeMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"srcSlotTxSlotPack","type":"bytes"},{"internalType":"bytes","name":"messageBytes","type":"bytes"},{"internalType":"bytes32[]","name":"receiptsRootProof","type":"bytes32[]"},{"internalType":"bytes32","name":"receiptsRoot","type":"bytes32"},{"internalType":"bytes[]","name":"receiptProof","type":"bytes[]"},{"internalType":"bytes","name":"txIndexRLPEncoded","type":"bytes"},{"internalType":"uint256","name":"logIndex","type":"uint256"}],"name":"executeMessageFromLog","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"chainId","type":"uint32"}],"name":"freeze","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"freezeAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"frozen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32[]","name":"_sourceChainIds","type":"uint32[]"},{"internalType":"address[]","name":"_lightClients","type":"address[]"},{"internalType":"address[]","name":"_broadcasters","type":"address[]"},{"internalType":"address","name":"_timelock","type":"address"},{"internalType":"address","name":"_guardian","type":"address"},{"internalType":"bool","name":"_sendingEnabled","type":"bool"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"}],"name":"lightClients","outputs":[{"internalType":"contract ILightClient","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"messageStatus","outputs":[{"internalType":"enum MessageStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"messages","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"recipientChainId","type":"uint32"},{"internalType":"address","name":"recipientAddress","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"send","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"recipientChainId","type":"uint32"},{"internalType":"bytes32","name":"recipientAddress","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"send","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"recipientChainId","type":"uint32"},{"internalType":"address","name":"recipientAddress","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"sendViaStorage","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"recipientChainId","type":"uint32"},{"internalType":"bytes32","name":"recipientAddress","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"sendViaStorage","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sendingEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"chainId","type":"uint32"},{"internalType":"address","name":"lightclient","type":"address"},{"internalType":"address","name":"broadcaster","type":"address"}],"name":"setLightClientAndBroadcaster","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setSendingEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"sourceChainIds","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sourceChainIdsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"storageRootCache","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"chainId","type":"uint32"}],"name":"unfreeze","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unfreezeAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60a0604052306080523480156200001557600080fd5b506200002062000026565b620000e8565b603254610100900460ff1615620000935760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60325460ff9081161015620000e6576032805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b608051615f3662000120600039600081816109f701528181610a3701528181610d9f01528181610ddf0152610e6e0152615f366000f3fe6080604052600436106102255760003560e01c806366c5c4a0116101235780639a2ed203116100ab578063d547741f1161006f578063d547741f146106fb578063e4407b151461071b578063ed762d4414610730578063f288a2e214610750578063ffa1ad741461077257600080fd5b80639a2ed203146106395780639efeff1c14610659578063a217fddf1461068e578063a96a2e92146106a3578063affed0e0146106c357600080fd5b80637acc6754116100f25780637acc6754146105975780638d080d1d146105b757806391cd8bfd146105e457806391d148541461060457806399464c891461062457600080fd5b806366c5c4a01461050c57806368346a92146105215780636fdbccbf146105415780637599735c1461056157600080fd5b806336ae7c18116101b15780634f1ef286116101755780634f1ef2861461044a57806352d1902d1461045d57806354fd4d501461047257806359f897871461049e5780635cb77819146104ec57600080fd5b806336ae7c181461038e57806337d5af84146103be5780633c6cf473146103de5780633e99e9ce1461041b5780634552f5631461043557600080fd5b8063248a9ca3116101f8578063248a9ca3146102dc57806324ea54f41461030c5780632f2ff15d1461032e57806336568abe1461034e5780633659cfe61461036e57600080fd5b806301ffc9a71461022a578063029d67131461025f578063147bce491461029a5780631f3d25a9146102ba575b600080fd5b34801561023657600080fd5b5061024a610245366004614f74565b610787565b60405190151581526020015b60405180910390f35b34801561026b57600080fd5b5061028c61027a366004614fad565b60016020526000908152604090205481565b604051908152602001610256565b3480156102a657600080fd5b5061028c6102b5366004615034565b6107be565b3480156102c657600080fd5b506102da6102d5366004615094565b6108cb565b005b3480156102e857600080fd5b5061028c6102f73660046150af565b600090815260c9602052604090206001015490565b34801561031857600080fd5b5061028c600080516020615ee183398151915281565b34801561033a57600080fd5b506102da6103493660046150c8565b610945565b34801561035a57600080fd5b506102da6103693660046150c8565b61096f565b34801561037a57600080fd5b506102da6103893660046150f4565b6109ed565b34801561039a57600080fd5b5061024a6103a9366004615094565b60066020526000908152604090205460ff1681565b3480156103ca57600080fd5b506102da6103d9366004615208565b610acc565b3480156103ea57600080fd5b5061040e6103f93660046150af565b60076020526000908152604090205460ff1681565b604051610256919061531b565b34801561042757600080fd5b5060005461024a9060ff1681565b34801561044157600080fd5b5060035461028c565b6102da610458366004615343565b610d95565b34801561046957600080fd5b5061028c610e61565b34801561047e57600080fd5b5060085461048c9060ff1681565b60405160ff9091168152602001610256565b3480156104aa57600080fd5b506104d46104b9366004615094565b6005602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610256565b3480156104f857600080fd5b506102da61050736600461543e565b610f14565b34801561051857600080fd5b506102da611217565b34801561052d57600080fd5b5061028c61053c366004615034565b6112fc565b34801561054d57600080fd5b5061028c61055c366004615552565b61137b565b34801561056d57600080fd5b506104d461057c366004615094565b6004602052600090815260409020546001600160a01b031681565b3480156105a357600080fd5b506102da6105b2366004615593565b6113d2565b3480156105c357600080fd5b5061028c6105d23660046150af565b60096020526000908152604090205481565b3480156105f057600080fd5b506102da6105ff36600461563d565b6116e7565b34801561061057600080fd5b5061024a61061f3660046150c8565b611898565b34801561063057600080fd5b506102da6118c3565b34801561064557600080fd5b506102da610654366004615094565b6119a8565b34801561066557600080fd5b506106796106743660046150af565b611a25565b60405163ffffffff9091168152602001610256565b34801561069a57600080fd5b5061028c600081565b3480156106af57600080fd5b5061028c6106be366004615552565b611a5f565b3480156106cf57600080fd5b506002546106e3906001600160401b031681565b6040516001600160401b039091168152602001610256565b34801561070757600080fd5b506102da6107163660046150c8565b611ab6565b34801561072757600080fd5b5061028c607881565b34801561073c57600080fd5b506102da61074b366004615680565b611adb565b34801561075c57600080fd5b5061028c600080516020615e5a83398151915281565b34801561077e57600080fd5b5061048c600181565b60006001600160e01b03198216637965db0b60e01b14806107b857506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000805460ff166107ea5760405162461bcd60e51b81526004016107e19061569d565b60405180910390fd5b468563ffffffff160361080f5760405162461bcd60e51b81526004016107e1906156ca565b600080610828876001600160a01b0388165b8787611b56565b600280546001600160401b03908116600090815260016020526040812084905582549496509294508493169161085d83615717565b91906101000a8154816001600160401b0302191690836001600160401b031602179055506001600160401b03167fe5944a34d67c652e0ebf2304b48432aae0b55e40f79ba8a21a4d7054c169ffac846040516108b9919061578d565b60405180910390a39695505050505050565b6108e3600080516020615ee183398151915233611898565b6108ff5760405162461bcd60e51b81526004016107e1906157a0565b63ffffffff8116600081815260066020526040808220805460ff19169055517f9fd67bd682613b07687b42f99d8b24402d09feabb75df93abdb26b8fcf9845839190a250565b600082815260c9602052604090206001015461096081611bcd565b61096a8383611bd7565b505050565b6001600160a01b03811633146109df5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084016107e1565b6109e98282611c5d565b5050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610a355760405162461bcd60e51b81526004016107e1906157f5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610a7e600080516020615e9a833981519152546001600160a01b031690565b6001600160a01b031614610aa45760405162461bcd60e51b81526004016107e190615841565b610aad81611cc4565b60408051600080825260208201909252610ac991839190611cf8565b50565b610ad4611e63565b600080610ae18b8b611ebc565b91509150610af28260400151612126565b610aff8260400151612255565b6000808e8e810190610b11919061588d565b91509150610b238285604001516122b1565b60408481015163ffffffff166000908152600460208190528282205492516356f90d7960e01b81526001600160401b0386169181019190915290916001600160a01b0316906356f90d7990602401602060405180830381865afa158015610b8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb291906158b7565b905080610bf95760405162461bcd60e51b8152602060048201526015602482015274486561646572526f6f74206973206d697373696e6760581b60448201526064016107e1565b6000610c3d8b8e8e808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508792508991508890506124e5565b905080610c8c5760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420726563656970747320726f6f742070726f6f66000000000060448201526064016107e1565b505050506000610cf1878790610ca291906158d0565b60408086015163ffffffff166000908152600560205220548a90889088906001600160a01b03167fe5944a34d67c652e0ebf2304b48432aae0b55e40f79ba8a21a4d7054c169ffac600261268d565b9050818114610d3a5760405162461bcd60e51b815260206004820152601560248201527424b73b30b634b21036b2b9b9b0b3b2903430b9b41760591b60448201526064016107e1565b50610d7c82828d8d8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612a4092505050565b5050610d886001603355565b5050505050505050505050565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610ddd5760405162461bcd60e51b81526004016107e1906157f5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316610e26600080516020615e9a833981519152546001600160a01b031690565b6001600160a01b031614610e4c5760405162461bcd60e51b81526004016107e190615841565b610e5582611cc4565b6109e982826001611cf8565b6000306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610f015760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c000000000000000060648201526084016107e1565b50600080516020615e9a83398151915290565b603254610100900460ff1615808015610f345750603254600160ff909116105b80610f4e5750303b158015610f4e575060325460ff166001145b610fb15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016107e1565b6032805460ff191660011790558015610fd4576032805461ff0019166101001790555b610fdc612bee565b610fe4612c1f565b610ffc600080516020615ee183398151915284611bd7565b611014600080516020615e5a83398151915285611bd7565b61101f600085611bd7565b611027612c1f565b855187511461103557600080fd5b845187511461104357600080fd5b86516110569060039060208a0190614e9a565b5060005b60035463ffffffff821610156111aa57868163ffffffff168151811061108257611082615937565b60200260200101516004600060038463ffffffff16815481106110a7576110a7615937565b90600052602060002090600891828204019190066004029054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550858163ffffffff168151811061112357611123615937565b60200260200101516005600060038463ffffffff168154811061114857611148615937565b6000918252602080832060088304015460079092166004026101000a90910463ffffffff168352820192909252604001902080546001600160a01b0319166001600160a01b0392909216919091179055806111a28161594d565b91505061105a565b506000805483151560ff1991821617909155600880549091166001179055801561120e576032805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b61122f600080516020615ee183398151915233611898565b61124b5760405162461bcd60e51b81526004016107e1906157a0565b60005b60035463ffffffff821610156112d05760006006600060038463ffffffff168154811061127d5761127d615937565b6000918252602080832060088304015460079092166004026101000a90910463ffffffff1683528201929092526040019020805460ff1916911515919091179055806112c88161594d565b91505061124e565b506040517fe6fdbf73945dd61794a752b9181ea29f77170a7b1ffd37e0a7ff9d2c6f7258b990600090a1565b6000805460ff1661131f5760405162461bcd60e51b81526004016107e19061569d565b468563ffffffff16036113445760405162461bcd60e51b81526004016107e1906156ca565b60008061135a876001600160a01b038816610821565b6002805492945090925082916001600160401b031690600061085d83615717565b6000805460ff1661139e5760405162461bcd60e51b81526004016107e19061569d565b468563ffffffff16036113c35760405162461bcd60e51b81526004016107e1906156ca565b60008061082887878787611b56565b6113da611e63565b6000806113e78888611ebc565b915091506113f88260400151612126565b6114058260400151612255565b6114138983604001516122b1565b60408281015163ffffffff811660009081526005602090815283822054845160e09490941b6001600160e01b0319168483015260c08e901b6001600160c01b031916602485015260601b6001600160601b031916602c840152835180840382018152928401845282519281019290922080825260099092529182205482036115c55760408085015163ffffffff16600090815260046020819052828220549251637623ee2960e01b81526001600160401b038f169181019190915290916001600160a01b031690637623ee2990602401602060405180830381865afa158015611500573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061152491906158b7565b905060008190036115775760405162461bcd60e51b815260206004820152601f60248201527f457865637574696f6e20537461746520526f6f74206973206e6f74207365740060448201526064016107e1565b6115ab611584898b6158d0565b60408088015163ffffffff166000908152600560205220546001600160a01b031683612c46565b600083815260096020526040902081905592506115d79050565b60008181526009602052604090205491505b6000846020015160016040516020016116059291906001600160401b03929092168252602082015260400190565b60408051808303601f1901815282825280516020918201208184015281518084038201815292820190915281519101209050600061164d82856116488a8c6158d0565b612d3d565b90508481146116965760405162461bcd60e51b815260206004820152601560248201527424b73b30b634b21036b2b9b9b0b3b2903430b9b41760591b60448201526064016107e1565b505050506116db82828a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612a4092505050565b505061120e6001603355565b6116ff600080516020615e5a83398151915233611898565b61171b5760405162461bcd60e51b81526004016107e190615966565b6000805b600354811015611787578463ffffffff166003828154811061174357611743615937565b6000918252602090912060088204015460079091166004026101000a900463ffffffff16036117755760019150611787565b8061177f816159bb565b91505061171f565b508061181057600380546001810182556000918252600881047fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01805463ffffffff80891660046007909516949094026101000a84810291021990911617905560405190917f65a791dc0a39717013964ace2b78f8307f275c293b7fdb425346ce8e18cb318891a25b63ffffffff8416600081815260046020908152604080832080546001600160a01b038981166001600160a01b031992831681179093556005855294839020805495891695909116851790558151908152918201929092527f0205eaadbbed4fbe918b2a594d41bceb212a89010cc678c6762b18d65679b2ef910160405180910390a250505050565b600091825260c9602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6118db600080516020615ee183398151915233611898565b6118f75760405162461bcd60e51b81526004016107e1906157a0565b60005b60035463ffffffff8216101561197c5760016006600060038463ffffffff168154811061192957611929615937565b6000918252602080832060088304015460079092166004026101000a90910463ffffffff1683528201929092526040019020805460ff1916911515919091179055806119748161594d565b9150506118fa565b506040517f61340a1b154d5d21d259a74bf95379201799b9d12cc6509bb46cb56dc281df5590600090a1565b6119c0600080516020615ee183398151915233611898565b6119dc5760405162461bcd60e51b81526004016107e1906157a0565b63ffffffff8116600081815260066020526040808220805460ff19166001179055517ff6cf9095f1dcea2429c26c832cbcc084fa0a1692b2c301601edd75b9d83520b29190a250565b60038181548110611a3557600080fd5b9060005260206000209060089182820401919006600402915054906101000a900463ffffffff1681565b6000805460ff16611a825760405162461bcd60e51b81526004016107e19061569d565b468563ffffffff1603611aa75760405162461bcd60e51b81526004016107e1906156ca565b60008061135a87878787611b56565b600082815260c96020526040902060010154611ad181611bcd565b61096a8383611c5d565b611af3600080516020615ee183398151915233611898565b611b0f5760405162461bcd60e51b81526004016107e1906157a0565b6000805460ff19168215159081179091556040519081527f3eea1dc6ce990571e1081137b38c853529a3893b52e9719a48a2f4ac5e3a956c9060200160405180910390a150565b600854600254604080516020601f8601819004810282018101909252848152606093600093611bb99360ff909216926001600160401b0390911691469133918c918c918c908c9081908401838280828437600092019190915250612dd992505050565b805160208201209097909650945050505050565b610ac98133612e14565b611be18282611898565b6109e957600082815260c9602090815260408083206001600160a01b03851684529091529020805460ff19166001179055611c193390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b611c678282611898565b156109e957600082815260c9602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b611cdc600080516020615e5a83398151915233611898565b610ac95760405162461bcd60e51b81526004016107e190615966565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615611d2b5761096a83612e6d565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611d85575060408051601f3d908101601f19168201909252611d82918101906158b7565b60015b611de85760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b60648201526084016107e1565b600080516020615e9a8339815191528114611e575760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b60648201526084016107e1565b5061096a838383612f09565b600260335403611eb55760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016107e1565b6002603355565b6040805160e08101825260008082526020820181905291810182905260608082018390526080820183905260a082019290925260c0810191909152600080611f3985858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612f3492505050565b905060008585604051611f4d9291906159d4565b60405190819003902090506000808281526007602052604090205460ff166002811115611f7c57611f7c615305565b14611fc95760405162461bcd60e51b815260206004820152601960248201527f4d65737361676520616c72656164792065786563757465642e0000000000000060448201526064016107e1565b46826080015163ffffffff16146120115760405162461bcd60e51b815260206004820152600c60248201526b2bb937b7339031b430b4b71760a11b60448201526064016107e1565b600854825160ff90811691161461205b5760405162461bcd60e51b815260206004820152600e60248201526d2bb937b733903b32b939b4b7b71760911b60448201526064016107e1565b60408083015163ffffffff166000908152600460205220546001600160a01b031615806120a6575060408083015163ffffffff166000908152600560205220546001600160a01b0316155b156121195760405162461bcd60e51b815260206004820152603760248201527f4c6967687420636c69656e74206f722062726f616463617374657220666f722060448201527f736f7572636520636861696e206973206e6f742073657400000000000000000060648201526084016107e1565b90925090505b9250929050565b63ffffffff81166000908152600460205260409020546001600160a01b031661218c5760405162461bcd60e51b81526020600482015260186024820152772634b3b43a1031b634b2b73a1034b9903737ba1039b2ba1760411b60448201526064016107e1565b63ffffffff8116600090815260046020818152604092839020548351632bcccca560e01b815293516001600160a01b0390911693632bcccca5938181019392918290030181865afa1580156121e5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061220991906159e4565b610ac95760405162461bcd60e51b815260206004820152601d60248201527f4c6967687420636c69656e7420697320696e636f6e73697374656e742e00000060448201526064016107e1565b63ffffffff811660009081526006602052604090205460ff1615610ac95760405162461bcd60e51b815260206004820152601360248201527221b7b73a3930b1ba1034b990333937bd32b71760691b60448201526064016107e1565b63ffffffff81166000908152600460205260409020546001600160a01b03166123175760405162461bcd60e51b81526020600482015260186024820152772634b3b43a1031b634b2b73a1034b9903737ba1039b2ba1760411b60448201526064016107e1565b63ffffffff8116600090815260046020819052604091829020549151638bc33af360e01b81526001600160401b038516918101919091526001600160a01b0390911690638bc33af390602401602060405180830381865afa158015612380573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123a491906158b7565b6000036123f35760405162461bcd60e51b815260206004820152601e60248201527f54696d657374616d70206973206e6f742073657420666f7220736c6f742e000060448201526064016107e1565b63ffffffff81166000908152600460208190526040808320549051638bc33af360e01b81526001600160401b038616928101929092526001600160a01b031690638bc33af390602401602060405180830381865afa158015612459573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061247d91906158b7565b6124879042615a01565b9050607881101561096a5760405162461bcd60e51b815260206004820152602260248201527f4d7573742077616974206c6f6e67657220746f20757365207468697320736c6f6044820152613a1760f11b60648201526084016107e1565b600080826001600160401b0316846001600160401b0316036125235750600b61251081610200615a14565b61251c90610183615a33565b9050612676565b6120006125308486615a46565b6001600160401b0316116125925750600b61254c816020615a14565b612557906006615a33565b905061256e6120006001600160401b038516615a83565b61257a61200083615a14565b6125849190615a33565b905061251081610200615a14565b836001600160401b0316836001600160401b031610156126245750600b6125ba816020615a14565b6125c5906007615a33565b90506125d2816002615a14565b6125dd906000615a33565b90506125f46120006001600160401b038516615a97565b612602630100000083615a14565b61260c9190615a33565b9050612619816002615a14565b612557906001615a33565b60405162461bcd60e51b815260206004820152602160248201527f54727573746c657373414d423a20696e76616c69642074617267657420736c6f6044820152601d60fa1b60648201526084016107e1565b61268287828888612ff9565b979650505050505050565b60008061269b878a8a613013565b90506000816000815181106126b2576126b2615937565b01602001516001600160f81b03191690506000600160f81b8214806126e45750600160f91b6001600160f81b03198316145b156126f157506001612756565b600360fe1b6001600160f81b031983161061270e57506000612756565b60405162461bcd60e51b815260206004820152601c60248201527f556e737570706f72746564207472616e73616374696f6e20747970650000000060448201526064016107e1565b6000602084019050600060405180604001604052808487516127789190615a01565b81526020016127878585615a33565b905290506000612796826138b3565b905080516004146127e25760405162461bcd60e51b8152602060048201526016602482015275092dcecc2d8d2c840e4cac6cad2e0e840d8cadccee8d60531b60448201526064016107e1565b6000612807826003815181106127fa576127fa615937565b60200260200101516138b3565b905080518c106128595760405162461bcd60e51b815260206004820152601760248201527f4c6f6720696e646578206f7574206f6620626f756e647300000000000000000060448201526064016107e1565b6000612870828e815181106127fa576127fa615937565b905080516003146128ce5760405162461bcd60e51b815260206004820152602260248201527f4c6f672068617320696e636f7272656374206e756d626572206f66206669656c604482015261647360f01b60648201526084016107e1565b60006128f3826000815181106128e6576128e6615937565b6020026020010151613ad8565b90508c6001600160a01b0316816001600160a01b0316146129665760405162461bcd60e51b815260206004820152602760248201527f4576656e7420776173206e6f7420656d697474656420627920636c61696d656460448201526622b6b4ba3a32b960c91b60648201526084016107e1565b600061297e836001815181106127fa576127fa615937565b90508c6129a48260008151811061299757612997615937565b6020026020010151613b42565b14612a075760405162461bcd60e51b815260206004820152602d60248201527f4576656e74207369676e617475726520646f6573206e6f74206d61746368206560448201526c76656e745369676e617475726560981b60648201526084016107e1565b612a29818d81518110612a1c57612a1c615937565b6020026020010151613b49565b9a5050505050505050505050979650505050505050565b600060606000633bdc60d660e01b866040015187606001518860c00151604051602401612a6f93929190615aab565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915260a0870151909150806001600160a01b031682604051612ac19190615adb565b6000604051808303816000865af19150503d8060008114612afe576040519150601f19603f3d011682016040523d82523d6000602084013e612b03565b606091505b5080519195509350600092506020039050612b4557600082806020019051810190612b2e9190615af7565b6001600160e01b031916631dee306b60e11b149150505b828015612b4f5750805b15612b72576000858152600760205260409020805460ff19166002179055612b8c565b6000858152600760205260409020805460ff191660011790555b8486602001516001600160401b0316876040015163ffffffff167f1f26985f3389d5ee1e49b37cdef193b3e98c927d7dd8b6a1f9cddd17a1fe89478787604051612bd7929190615b14565b60405180910390a4505050505050565b6001603355565b603254610100900460ff16612c155760405162461bcd60e51b81526004016107e190615b38565b612c1d613c4c565b565b603254610100900460ff16612c1d5760405162461bcd60e51b81526004016107e190615b38565b6040516001600160601b0319606084901b16602082015260009081906034016040516020818303038152906040528051906020012090506000612cab82604051602001612c9591815260200190565b6040516020818303038152906040528786613013565b90506000815111612cf75760405162461bcd60e51b81526020600482015260166024820152751058d8dbdd5b9d08191bd95cc81b9bdd08195e1a5cdd60521b60448201526064016107e1565b6000612d0a612d0583613c73565b6138b3565b90508051600414612d1a57600080fd5b612d308160028151811061299757612997615937565b93505050505b9392505050565b600080612d6c85604051602001612d5691815260200190565b6040516020818303038152906040528486613013565b90506000815111612dbf5760405162461bcd60e51b815260206004820152601c60248201527f53746f726167652076616c756520646f6573206e6f742065786973740000000060448201526064016107e1565b612dd0612dcb82613c73565b613b42565b95945050505050565b606087878787878787604051602001612df89796959493929190615b83565b6040516020818303038152906040529050979650505050505050565b612e1e8282611898565b6109e957612e2b81613cc6565b612e36836020613cd8565b604051602001612e47929190615c0a565b60408051601f198184030181529082905262461bcd60e51b82526107e19160040161578d565b6001600160a01b0381163b612eda5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016107e1565b600080516020615e9a83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b612f1283613e73565b600082511180612f1f5750805b1561096a57612f2e8383613eb3565b50505050565b6040805160e08101825260008082526020820181905291810182905260608082018390526080820183905260a082019290925260c081019190915260018201516009830151600d8401516021850151602586015160458088015160ff871688526001600160401b038616602089015263ffffffff80861660408a01526001600160a01b03851660608a01528316608089015260a0880181905288519091612fe8918a9190612fe3908290615a01565b613f9e565b60c088015250949695505050505050565b60008061300786868661408a565b90921495945050505050565b6060600084511161305e5760405162461bcd60e51b81526020600482015260156024820152744d65726b6c65547269653a20656d707479206b657960581b60448201526064016107e1565b600061306984614219565b9050600061307686614307565b905060008460405160200161308d91815260200190565b60405160208183030381529060405290506000805b845181101561385c5760008582815181106130bf576130bf615937565b6020026020010151905084518311156131315760405162461bcd60e51b815260206004820152602e60248201527f4d65726b6c65547269653a206b657920696e646578206578636565647320746f60448201526d0e8c2d840d6caf240d8cadccee8d60931b60648201526084016107e1565b826000036131d0578051805160209182012060405161317f9261315992910190815260200190565b604051602081830303815290604052858051602091820120825192909101919091201490565b6131cb5760405162461bcd60e51b815260206004820152601d60248201527f4d65726b6c65547269653a20696e76616c696420726f6f74206861736800000060448201526064016107e1565b6132c6565b80515160201161325657805180516020918201206040516131fa9261315992910190815260200190565b6131cb5760405162461bcd60e51b815260206004820152602760248201527f4d65726b6c65547269653a20696e76616c6964206c6172676520696e7465726e6044820152660c2d840d0c2e6d60cb1b60648201526084016107e1565b8051845160208087019190912082519190920120146132c65760405162461bcd60e51b815260206004820152602660248201527f4d65726b6c65547269653a20696e76616c696420696e7465726e616c206e6f646044820152650ca40d0c2e6d60d31b60648201526084016107e1565b6132d260106001615a33565b8160200151510361347f578451830361341757600061330e826020015160108151811061330157613301615937565b6020026020010151614421565b905060008151116133875760405162461bcd60e51b815260206004820152603b60248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286272616e636829000000000060648201526084016107e1565b600187516133959190615a01565b83146134095760405162461bcd60e51b815260206004820152603a60248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286272616e63682900000000000060648201526084016107e1565b9650612d3695505050505050565b600085848151811061342b5761342b615937565b602001015160f81c60f81b60f81c9050600082602001518260ff168151811061345657613456615937565b6020026020010151905061346981614544565b9550613476600186615a33565b94505050613849565b6002816020015151036137f057600061349782614569565b90506000816000815181106134ae576134ae615937565b016020015160f81c905060006134c5600283615c7f565b6134d0906002615ca1565b905060006134e1848360ff1661458d565b905060006134ef8a8961458d565b905060006134fd83836145c3565b9050808351146135755760405162461bcd60e51b815260206004820152603a60248201527f4d65726b6c65547269653a20706174682072656d61696e646572206d7573742060448201527f736861726520616c6c206e6962626c65732077697468206b657900000000000060648201526084016107e1565b60ff85166002148061358a575060ff85166003145b1561373057808251146136055760405162461bcd60e51b815260206004820152603d60248201527f4d65726b6c65547269653a206b65792072656d61696e646572206d757374206260448201527f65206964656e746963616c20746f20706174682072656d61696e64657200000060648201526084016107e1565b6000613621886020015160018151811061330157613301615937565b9050600081511161369a5760405162461bcd60e51b815260206004820152603960248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286c656166290000000000000060648201526084016107e1565b60018d516136a89190615a01565b891461371c5760405162461bcd60e51b815260206004820152603860248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286c65616629000000000000000060648201526084016107e1565b9c50612d369b505050505050505050505050565b60ff85161580613743575060ff85166001145b156137825761376f876020015160018151811061376257613762615937565b6020026020010151614544565b995061377b818a615a33565b98506137e5565b60405162461bcd60e51b815260206004820152603260248201527f4d65726b6c65547269653a2072656365697665642061206e6f64652077697468604482015271040c2dc40eadcd6dcdeeedc40e0e4caccd2f60731b60648201526084016107e1565b505050505050613849565b60405162461bcd60e51b815260206004820152602860248201527f4d65726b6c65547269653a20726563656976656420616e20756e706172736561604482015267626c65206e6f646560c01b60648201526084016107e1565b5080613854816159bb565b9150506130a2565b5060405162461bcd60e51b815260206004820152602560248201527f4d65726b6c65547269653a2072616e206f7574206f662070726f6f6620656c656044820152646d656e747360d81b60648201526084016107e1565b606060008060006138c385614642565b9194509250905060018160018111156138de576138de615305565b146139515760405162461bcd60e51b815260206004820152603860248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206c697374206973206e6f742061206c697374206974656d000000000000000060648201526084016107e1565b845161395d8385615a33565b146139c55760405162461bcd60e51b815260206004820152603260248201527f524c505265616465723a206c697374206974656d2068617320616e20696e76616044820152713634b2103230ba30903932b6b0b4b73232b960711b60648201526084016107e1565b6040805160208082526104208201909252600091816020015b60408051808201909152600080825260208201528152602001906001900390816139de5790505090506000845b8751811015613acc57600080613a516040518060400160405280858d60000151613a359190615a01565b8152602001858d60200151613a4a9190615a33565b9052614642565b509150915060405180604001604052808383613a6d9190615a33565b8152602001848c60200151613a829190615a33565b815250858581518110613a9757613a97615937565b6020908102919091010152613aad600185615a33565b9350613ab98183615a33565b613ac39084615a33565b92505050613a0b565b50815295945050505050565b8051600090600103613aec57506000919050565b8151601514613b3d5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020616464726573732076616c75652e00000000000060448201526064016107e1565b6107b8825b60006107b8825b6000602182600001511115613ba05760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e00000000000060448201526064016107e1565b6000806000613bae85614642565b919450925090506000816001811115613bc957613bc9615305565b14613c165760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e00000000000060448201526064016107e1565b6000838660200151613c289190615a33565b80519091506020841015613c425760208490036101000a90045b9695505050505050565b603254610100900460ff16612be75760405162461bcd60e51b81526004016107e190615b38565b60408051808201909152600080825260208201526000825111613ca85760405162461bcd60e51b81526004016107e190615cba565b50604080518082019091528151815260209182019181019190915290565b60606107b86001600160a01b03831660145b60606000613ce7836002615a14565b613cf2906002615a33565b6001600160401b03811115613d0957613d09615153565b6040519080825280601f01601f191660200182016040528015613d33576020820181803683370190505b509050600360fc1b81600081518110613d4e57613d4e615937565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110613d7d57613d7d615937565b60200101906001600160f81b031916908160001a9053506000613da1846002615a14565b613dac906001615a33565b90505b6001811115613e24576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110613de057613de0615937565b1a60f81b828281518110613df657613df6615937565b60200101906001600160f81b031916908160001a90535060049490941c93613e1d81615d2a565b9050613daf565b508315612d365760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016107e1565b613e7c81612e6d565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606001600160a01b0383163b613f1b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016107e1565b600080846001600160a01b031684604051613f369190615adb565b600060405180830381855af49150503d8060008114613f71576040519150601f19603f3d011682016040523d82523d6000602084013e613f76565b606091505b5091509150612dd08282604051806060016040528060278152602001615eba60279139614d05565b606081613fac81601f615a33565b1015613fca5760405162461bcd60e51b81526004016107e190615d41565b613fd48284615a33565b845110156140185760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b60448201526064016107e1565b6060821580156140375760405191506000825260208201604052614081565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015614070578051835260209283019201614058565b5050858452601f01601f1916604052505b50949350505050565b6000828251600161409b9190615a33565b6140a6906002615e4d565b116140b057600080fd5b8360005b84600114614081576140c7600286615a83565b6001036141665760028482815181106140e2576140e2615937565b602002602001015183604051602001614105929190918252602082015260400190565b60408051601f198184030181529082905261411f91615adb565b602060405180830381855afa15801561413c573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061415f91906158b7565b91506141fa565b60028285838151811061417b5761417b615937565b602002602001015160405160200161419d929190918252602082015260400190565b60408051601f19818403018152908290526141b791615adb565b602060405180830381855afa1580156141d4573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906141f791906158b7565b91505b614205600286615a97565b945080614211816159bb565b9150506140b4565b80516060906000816001600160401b0381111561423857614238615153565b60405190808252806020026020018201604052801561427d57816020015b60408051808201909152606080825260208201528152602001906001900390816142565790505b50905060005b828110156142ff5760405180604001604052808683815181106142a8576142a8615937565b602002602001015181526020016142d78784815181106142ca576142ca615937565b6020026020010151614d1e565b8152508282815181106142ec576142ec615937565b6020908102919091010152600101614283565b509392505050565b80516060906000614319826002615a14565b6001600160401b0381111561433057614330615153565b6040519080825280601f01601f19166020018201604052801561435a576020820181803683370190505b5090506000805b838110156144175785818151811061437b5761437b615937565b6020910101516001600160f81b03198116925060041c60ff60f41b16836143a3836002615a14565b815181106143b3576143b3615937565b60200101906001600160f81b031916908160001a905350600f60f81b8216836143dd836002615a14565b6143e8906001615a33565b815181106143f8576143f8615937565b60200101906001600160f81b031916908160001a905350600101614361565b5090949350505050565b6060600080600061443185614642565b91945092509050600081600181111561444c5761444c615305565b146144bf5760405162461bcd60e51b815260206004820152603960248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206279746573206973206e6f7420612064617461206974656d0000000000000060648201526084016107e1565b6144c98284615a33565b8551146145355760405162461bcd60e51b815260206004820152603460248201527f524c505265616465723a2062797465732076616c756520636f6e7461696e732060448201527330b71034b73b30b634b2103932b6b0b4b73232b960611b60648201526084016107e1565b612dd085602001518484614d2c565b606060208260000151106145605761455b82614421565b6107b8565b6107b882614dcc565b60606107b8614588836020015160008151811061330157613301615937565b614307565b6060825182106145ac57506040805160208101909152600081526107b8565b612d3683838486516145be9190615a01565b614de2565b600080600083518551106145d85783516145db565b84515b90505b808210801561463257508382815181106145fa576145fa615937565b602001015160f81c60f81b6001600160f81b03191685838151811061462157614621615937565b01602001516001600160f81b031916145b156142ff578160010191506145de565b60008060008084600001511161466a5760405162461bcd60e51b81526004016107e190615cba565b6020840151805160001a607f811161468f576000600160009450945094505050614cfe565b60b781116147ec5760006146a4608083615a01565b9050808760000151116147245760405162461bcd60e51b815260206004820152604e6024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e20737472696e67206c656e6774682060648201526d2873686f727420737472696e672960901b608482015260a4016107e1565b6001838101516001600160f81b03191690821415806147515750600160ff1b6001600160f81b0319821610155b6147d95760405162461bcd60e51b815260206004820152604d60248201527f524c505265616465723a20696e76616c6964207072656669782c2073696e676c60448201527f652062797465203c203078383020617265206e6f74207072656669786564202860648201526c73686f727420737472696e672960981b608482015260a4016107e1565b5060019550935060009250614cfe915050565b60bf8111614a2d57600061480160b783615a01565b9050808760000151116148845760405162461bcd60e51b81526020600482015260516024820152600080516020615e7a83398151915260448201527f74206265203e207468616e206c656e677468206f6620737472696e67206c656e60648201527067746820286c6f6e6720737472696e672960781b608482015260a4016107e1565b60018301516001600160f81b031916600081900361490b5760405162461bcd60e51b815260206004820152604a6024820152600080516020615e7a83398151915260448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f6064820152696e6720737472696e672960b01b608482015260a4016107e1565b600184015160088302610100031c6037811161498e5760405162461bcd60e51b81526020600482015260486024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e20353520627974657320286c6f6e6760648201526720737472696e672960c01b608482015260a4016107e1565b6149988184615a33565b895111614a105760405162461bcd60e51b815260206004820152604c6024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e20746f74616c206c656e677468202860648201526b6c6f6e6720737472696e672960a01b608482015260a4016107e1565b614a1b836001615a33565b9750955060009450614cfe9350505050565b60f78111614acf576000614a4260c083615a01565b905080876000015111614abe5760405162461bcd60e51b815260206004820152604a6024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e206c697374206c656e677468202873606482015269686f7274206c6973742960b01b608482015260a4016107e1565b600195509350849250614cfe915050565b6000614adc60f783615a01565b905080876000015111614b5b5760405162461bcd60e51b815260206004820152604d6024820152600080516020615e7a83398151915260448201527f74206265203e207468616e206c656e677468206f66206c697374206c656e677460648201526c6820286c6f6e67206c6973742960981b608482015260a4016107e1565b60018301516001600160f81b0319166000819003614be05760405162461bcd60e51b81526020600482015260486024820152600080516020615e7a83398151915260448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f6064820152676e67206c6973742960c01b608482015260a4016107e1565b600184015160088302610100031c60378111614c615760405162461bcd60e51b81526020600482015260466024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e20353520627974657320286c6f6e67606482015265206c6973742960d01b608482015260a4016107e1565b614c6b8184615a33565b895111614ce15760405162461bcd60e51b815260206004820152604a6024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e20746f74616c206c656e67746820286064820152696c6f6e67206c6973742960b01b608482015260a4016107e1565b614cec836001615a33565b9750955060019450614cfe9350505050565b9193909250565b60608315614d14575081612d36565b612d368383614e70565b60606107b8612d0583613c73565b60606000826001600160401b03811115614d4857614d48615153565b6040519080825280601f01601f191660200182016040528015614d72576020820181803683370190505b50905082600003614d84579050612d36565b6000614d908587615a33565b90506020820160005b85811015614db1578281015182820152602001614d99565b85811115614dc0576000868301525b50919695505050505050565b60606107b8826020015160008460000151614d2c565b60608182601f011015614e075760405162461bcd60e51b81526004016107e190615d41565b828284011015614e295760405162461bcd60e51b81526004016107e190615d41565b818301845110156140185760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b60448201526064016107e1565b815115614e805781518083602001fd5b8060405162461bcd60e51b81526004016107e1919061578d565b82805482825590600052602060002090600701600890048101928215614f395791602002820160005b83821115614f0757835183826101000a81548163ffffffff021916908363ffffffff1602179055509260200192600401602081600301049283019260010302614ec3565b8015614f375782816101000a81549063ffffffff0219169055600401602081600301049283019260010302614f07565b505b50614f45929150614f49565b5090565b5b80821115614f455760008155600101614f4a565b6001600160e01b031981168114610ac957600080fd5b600060208284031215614f8657600080fd5b8135612d3681614f5e565b80356001600160401b0381168114614fa857600080fd5b919050565b600060208284031215614fbf57600080fd5b612d3682614f91565b803563ffffffff81168114614fa857600080fd5b80356001600160a01b0381168114614fa857600080fd5b60008083601f84011261500557600080fd5b5081356001600160401b0381111561501c57600080fd5b60208301915083602082850101111561211f57600080fd5b6000806000806060858703121561504a57600080fd5b61505385614fc8565b935061506160208601614fdc565b925060408501356001600160401b0381111561507c57600080fd5b61508887828801614ff3565b95989497509550505050565b6000602082840312156150a657600080fd5b612d3682614fc8565b6000602082840312156150c157600080fd5b5035919050565b600080604083850312156150db57600080fd5b823591506150eb60208401614fdc565b90509250929050565b60006020828403121561510657600080fd5b612d3682614fdc565b60008083601f84011261512157600080fd5b5081356001600160401b0381111561513857600080fd5b6020830191508360208260051b850101111561211f57600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561519157615191615153565b604052919050565b600082601f8301126151aa57600080fd5b81356001600160401b038111156151c3576151c3615153565b6151d6601f8201601f1916602001615169565b8181528460208386010111156151eb57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600080600080600080600060e08c8e03121561522957600080fd5b6001600160401b03808d35111561523f57600080fd5b61524c8e8e358f01614ff3565b909c509a5060208d013581101561526257600080fd5b6152728e60208f01358f01614ff3565b909a50985060408d013581101561528857600080fd5b6152988e60408f01358f0161510f565b909850965060608d0135955060808d01358110156152b557600080fd5b6152c58e60808f01358f0161510f565b909550935060a08d01358110156152db57600080fd5b506152ec8d60a08e01358e01615199565b915060c08c013590509295989b509295989b9093969950565b634e487b7160e01b600052602160045260246000fd5b602081016003831061533d57634e487b7160e01b600052602160045260246000fd5b91905290565b6000806040838503121561535657600080fd5b61535f83614fdc565b915060208301356001600160401b0381111561537a57600080fd5b61538685828601615199565b9150509250929050565b60006001600160401b038211156153a9576153a9615153565b5060051b60200190565b600082601f8301126153c457600080fd5b813560206153d96153d483615390565b615169565b82815260059290921b840181019181810190868411156153f857600080fd5b8286015b8481101561541a5761540d81614fdc565b83529183019183016153fc565b509695505050505050565b8015158114610ac957600080fd5b8035614fa881615425565b60008060008060008060c0878903121561545757600080fd5b86356001600160401b038082111561546e57600080fd5b818901915089601f83011261548257600080fd5b813560206154926153d483615390565b82815260059290921b8401810191818101908d8411156154b157600080fd5b948201945b838610156154d6576154c786614fc8565b825294820194908201906154b6565b9a50508a0135925050808211156154ec57600080fd5b6154f88a838b016153b3565b9650604089013591508082111561550e57600080fd5b5061551b89828a016153b3565b94505061552a60608801614fdc565b925061553860808801614fdc565b915061554660a08801615433565b90509295509295509295565b6000806000806060858703121561556857600080fd5b61557185614fc8565b93506020850135925060408501356001600160401b0381111561507c57600080fd5b60008060008060008060006080888a0312156155ae57600080fd5b6155b788614f91565b965060208801356001600160401b03808211156155d357600080fd5b6155df8b838c01614ff3565b909850965060408a01359150808211156155f857600080fd5b6156048b838c0161510f565b909650945060608a013591508082111561561d57600080fd5b5061562a8a828b0161510f565b989b979a50959850939692959293505050565b60008060006060848603121561565257600080fd5b61565b84614fc8565b925061566960208501614fdc565b915061567760408501614fdc565b90509250925092565b60006020828403121561569257600080fd5b8135612d3681615425565b60208082526013908201527214d95b991a5b99c81a5cc8191a5cd8589b1959606a1b604082015260600190565b60208082526019908201527f43616e6e6f742073656e6420746f2073616d6520636861696e00000000000000604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60006001600160401b0380831681810361573357615733615701565b6001019392505050565b60005b83811015615758578181015183820152602001615740565b50506000910152565b6000815180845261577981602086016020860161573d565b601f01601f19169290920160200192915050565b602081526000612d366020830184615761565b60208082526035908201527f54656c657061746879526f757465723a206f6e6c7920677561726469616e206360408201527430b71031b0b636103a3434b990333ab731ba34b7b760591b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b600080604083850312156158a057600080fd5b6158a983614f91565b91506150eb60208401614f91565b6000602082840312156158c957600080fd5b5051919050565b60006158de6153d484615390565b80848252602080830192508560051b8501368111156158fc57600080fd5b855b81811015614dc05780356001600160401b0381111561591d5760008081fd5b61592936828a01615199565b8652509382019382016158fe565b634e487b7160e01b600052603260045260246000fd5b600063ffffffff80831681810361573357615733615701565b60208082526035908201527f54656c657061746879526f757465723a206f6e6c792074696d656c6f636b206360408201527430b71031b0b636103a3434b990333ab731ba34b7b760591b606082015260800190565b6000600182016159cd576159cd615701565b5060010190565b8183823760009101908152919050565b6000602082840312156159f657600080fd5b8151612d3681615425565b818103818111156107b8576107b8615701565b6000816000190483118215151615615a2e57615a2e615701565b500290565b808201808211156107b8576107b8615701565b6001600160401b03828116828216039080821115615a6657615a66615701565b5092915050565b634e487b7160e01b600052601260045260246000fd5b600082615a9257615a92615a6d565b500690565b600082615aa657615aa6615a6d565b500490565b63ffffffff841681526001600160a01b0383166020820152606060408201819052600090612dd090830184615761565b60008251615aed81846020870161573d565b9190910192915050565b600060208284031215615b0957600080fd5b8151612d3681614f5e565b604081526000615b276040830185615761565b905082151560208301529392505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160f81b031960f889901b1681526001600160c01b031960c088901b1660018201526001600160e01b031960e087811b821660098401526001600160601b0319606088901b16600d84015285901b166021820152602581018390528151600090615bf781604585016020870161573d565b9190910160450198975050505050505050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351615c4281601785016020880161573d565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351615c7381602884016020880161573d565b01602801949350505050565b600060ff831680615c9257615c92615a6d565b8060ff84160691505092915050565b60ff82811682821603908111156107b8576107b8615701565b6020808252604a908201527f524c505265616465723a206c656e677468206f6620616e20524c50206974656d60408201527f206d7573742062652067726561746572207468616e207a65726f20746f206265606082015269206465636f6461626c6560b01b608082015260a00190565b600081615d3957615d39615701565b506000190190565b6020808252600e908201526d736c6963655f6f766572666c6f7760901b604082015260600190565b600181815b80851115615da4578160001904821115615d8a57615d8a615701565b80851615615d9757918102915b93841c9390800290615d6e565b509250929050565b600082615dbb575060016107b8565b81615dc8575060006107b8565b8160018114615dde5760028114615de857615e04565b60019150506107b8565b60ff841115615df957615df9615701565b50506001821b6107b8565b5060208310610133831016604e8410600b8410161715615e27575081810a6107b8565b615e318383615d69565b8060001904821115615e4557615e45615701565b029392505050565b6000612d368383615dac56fef66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05524c505265616465723a206c656e677468206f6620636f6e74656e74206d7573360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c656455435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041a2646970667358221220f69b1c44e29eed792424bef643e588366626efef00e60b2c59813e1a349096ed64736f6c63430008100033
Deployed Bytecode
0x6080604052600436106102255760003560e01c806366c5c4a0116101235780639a2ed203116100ab578063d547741f1161006f578063d547741f146106fb578063e4407b151461071b578063ed762d4414610730578063f288a2e214610750578063ffa1ad741461077257600080fd5b80639a2ed203146106395780639efeff1c14610659578063a217fddf1461068e578063a96a2e92146106a3578063affed0e0146106c357600080fd5b80637acc6754116100f25780637acc6754146105975780638d080d1d146105b757806391cd8bfd146105e457806391d148541461060457806399464c891461062457600080fd5b806366c5c4a01461050c57806368346a92146105215780636fdbccbf146105415780637599735c1461056157600080fd5b806336ae7c18116101b15780634f1ef286116101755780634f1ef2861461044a57806352d1902d1461045d57806354fd4d501461047257806359f897871461049e5780635cb77819146104ec57600080fd5b806336ae7c181461038e57806337d5af84146103be5780633c6cf473146103de5780633e99e9ce1461041b5780634552f5631461043557600080fd5b8063248a9ca3116101f8578063248a9ca3146102dc57806324ea54f41461030c5780632f2ff15d1461032e57806336568abe1461034e5780633659cfe61461036e57600080fd5b806301ffc9a71461022a578063029d67131461025f578063147bce491461029a5780631f3d25a9146102ba575b600080fd5b34801561023657600080fd5b5061024a610245366004614f74565b610787565b60405190151581526020015b60405180910390f35b34801561026b57600080fd5b5061028c61027a366004614fad565b60016020526000908152604090205481565b604051908152602001610256565b3480156102a657600080fd5b5061028c6102b5366004615034565b6107be565b3480156102c657600080fd5b506102da6102d5366004615094565b6108cb565b005b3480156102e857600080fd5b5061028c6102f73660046150af565b600090815260c9602052604090206001015490565b34801561031857600080fd5b5061028c600080516020615ee183398151915281565b34801561033a57600080fd5b506102da6103493660046150c8565b610945565b34801561035a57600080fd5b506102da6103693660046150c8565b61096f565b34801561037a57600080fd5b506102da6103893660046150f4565b6109ed565b34801561039a57600080fd5b5061024a6103a9366004615094565b60066020526000908152604090205460ff1681565b3480156103ca57600080fd5b506102da6103d9366004615208565b610acc565b3480156103ea57600080fd5b5061040e6103f93660046150af565b60076020526000908152604090205460ff1681565b604051610256919061531b565b34801561042757600080fd5b5060005461024a9060ff1681565b34801561044157600080fd5b5060035461028c565b6102da610458366004615343565b610d95565b34801561046957600080fd5b5061028c610e61565b34801561047e57600080fd5b5060085461048c9060ff1681565b60405160ff9091168152602001610256565b3480156104aa57600080fd5b506104d46104b9366004615094565b6005602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610256565b3480156104f857600080fd5b506102da61050736600461543e565b610f14565b34801561051857600080fd5b506102da611217565b34801561052d57600080fd5b5061028c61053c366004615034565b6112fc565b34801561054d57600080fd5b5061028c61055c366004615552565b61137b565b34801561056d57600080fd5b506104d461057c366004615094565b6004602052600090815260409020546001600160a01b031681565b3480156105a357600080fd5b506102da6105b2366004615593565b6113d2565b3480156105c357600080fd5b5061028c6105d23660046150af565b60096020526000908152604090205481565b3480156105f057600080fd5b506102da6105ff36600461563d565b6116e7565b34801561061057600080fd5b5061024a61061f3660046150c8565b611898565b34801561063057600080fd5b506102da6118c3565b34801561064557600080fd5b506102da610654366004615094565b6119a8565b34801561066557600080fd5b506106796106743660046150af565b611a25565b60405163ffffffff9091168152602001610256565b34801561069a57600080fd5b5061028c600081565b3480156106af57600080fd5b5061028c6106be366004615552565b611a5f565b3480156106cf57600080fd5b506002546106e3906001600160401b031681565b6040516001600160401b039091168152602001610256565b34801561070757600080fd5b506102da6107163660046150c8565b611ab6565b34801561072757600080fd5b5061028c607881565b34801561073c57600080fd5b506102da61074b366004615680565b611adb565b34801561075c57600080fd5b5061028c600080516020615e5a83398151915281565b34801561077e57600080fd5b5061048c600181565b60006001600160e01b03198216637965db0b60e01b14806107b857506301ffc9a760e01b6001600160e01b03198316145b92915050565b6000805460ff166107ea5760405162461bcd60e51b81526004016107e19061569d565b60405180910390fd5b468563ffffffff160361080f5760405162461bcd60e51b81526004016107e1906156ca565b600080610828876001600160a01b0388165b8787611b56565b600280546001600160401b03908116600090815260016020526040812084905582549496509294508493169161085d83615717565b91906101000a8154816001600160401b0302191690836001600160401b031602179055506001600160401b03167fe5944a34d67c652e0ebf2304b48432aae0b55e40f79ba8a21a4d7054c169ffac846040516108b9919061578d565b60405180910390a39695505050505050565b6108e3600080516020615ee183398151915233611898565b6108ff5760405162461bcd60e51b81526004016107e1906157a0565b63ffffffff8116600081815260066020526040808220805460ff19169055517f9fd67bd682613b07687b42f99d8b24402d09feabb75df93abdb26b8fcf9845839190a250565b600082815260c9602052604090206001015461096081611bcd565b61096a8383611bd7565b505050565b6001600160a01b03811633146109df5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b60648201526084016107e1565b6109e98282611c5d565b5050565b6001600160a01b037f0000000000000000000000000764f94b058da4f3dc480e038c35d2a6f7a7ef78163003610a355760405162461bcd60e51b81526004016107e1906157f5565b7f0000000000000000000000000764f94b058da4f3dc480e038c35d2a6f7a7ef786001600160a01b0316610a7e600080516020615e9a833981519152546001600160a01b031690565b6001600160a01b031614610aa45760405162461bcd60e51b81526004016107e190615841565b610aad81611cc4565b60408051600080825260208201909252610ac991839190611cf8565b50565b610ad4611e63565b600080610ae18b8b611ebc565b91509150610af28260400151612126565b610aff8260400151612255565b6000808e8e810190610b11919061588d565b91509150610b238285604001516122b1565b60408481015163ffffffff166000908152600460208190528282205492516356f90d7960e01b81526001600160401b0386169181019190915290916001600160a01b0316906356f90d7990602401602060405180830381865afa158015610b8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb291906158b7565b905080610bf95760405162461bcd60e51b8152602060048201526015602482015274486561646572526f6f74206973206d697373696e6760581b60448201526064016107e1565b6000610c3d8b8e8e808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508792508991508890506124e5565b905080610c8c5760405162461bcd60e51b815260206004820152601b60248201527f496e76616c696420726563656970747320726f6f742070726f6f66000000000060448201526064016107e1565b505050506000610cf1878790610ca291906158d0565b60408086015163ffffffff166000908152600560205220548a90889088906001600160a01b03167fe5944a34d67c652e0ebf2304b48432aae0b55e40f79ba8a21a4d7054c169ffac600261268d565b9050818114610d3a5760405162461bcd60e51b815260206004820152601560248201527424b73b30b634b21036b2b9b9b0b3b2903430b9b41760591b60448201526064016107e1565b50610d7c82828d8d8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612a4092505050565b5050610d886001603355565b5050505050505050505050565b6001600160a01b037f0000000000000000000000000764f94b058da4f3dc480e038c35d2a6f7a7ef78163003610ddd5760405162461bcd60e51b81526004016107e1906157f5565b7f0000000000000000000000000764f94b058da4f3dc480e038c35d2a6f7a7ef786001600160a01b0316610e26600080516020615e9a833981519152546001600160a01b031690565b6001600160a01b031614610e4c5760405162461bcd60e51b81526004016107e190615841565b610e5582611cc4565b6109e982826001611cf8565b6000306001600160a01b037f0000000000000000000000000764f94b058da4f3dc480e038c35d2a6f7a7ef781614610f015760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c000000000000000060648201526084016107e1565b50600080516020615e9a83398151915290565b603254610100900460ff1615808015610f345750603254600160ff909116105b80610f4e5750303b158015610f4e575060325460ff166001145b610fb15760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016107e1565b6032805460ff191660011790558015610fd4576032805461ff0019166101001790555b610fdc612bee565b610fe4612c1f565b610ffc600080516020615ee183398151915284611bd7565b611014600080516020615e5a83398151915285611bd7565b61101f600085611bd7565b611027612c1f565b855187511461103557600080fd5b845187511461104357600080fd5b86516110569060039060208a0190614e9a565b5060005b60035463ffffffff821610156111aa57868163ffffffff168151811061108257611082615937565b60200260200101516004600060038463ffffffff16815481106110a7576110a7615937565b90600052602060002090600891828204019190066004029054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200190815260200160002060006101000a8154816001600160a01b0302191690836001600160a01b03160217905550858163ffffffff168151811061112357611123615937565b60200260200101516005600060038463ffffffff168154811061114857611148615937565b6000918252602080832060088304015460079092166004026101000a90910463ffffffff168352820192909252604001902080546001600160a01b0319166001600160a01b0392909216919091179055806111a28161594d565b91505061105a565b506000805483151560ff1991821617909155600880549091166001179055801561120e576032805461ff0019169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b61122f600080516020615ee183398151915233611898565b61124b5760405162461bcd60e51b81526004016107e1906157a0565b60005b60035463ffffffff821610156112d05760006006600060038463ffffffff168154811061127d5761127d615937565b6000918252602080832060088304015460079092166004026101000a90910463ffffffff1683528201929092526040019020805460ff1916911515919091179055806112c88161594d565b91505061124e565b506040517fe6fdbf73945dd61794a752b9181ea29f77170a7b1ffd37e0a7ff9d2c6f7258b990600090a1565b6000805460ff1661131f5760405162461bcd60e51b81526004016107e19061569d565b468563ffffffff16036113445760405162461bcd60e51b81526004016107e1906156ca565b60008061135a876001600160a01b038816610821565b6002805492945090925082916001600160401b031690600061085d83615717565b6000805460ff1661139e5760405162461bcd60e51b81526004016107e19061569d565b468563ffffffff16036113c35760405162461bcd60e51b81526004016107e1906156ca565b60008061082887878787611b56565b6113da611e63565b6000806113e78888611ebc565b915091506113f88260400151612126565b6114058260400151612255565b6114138983604001516122b1565b60408281015163ffffffff811660009081526005602090815283822054845160e09490941b6001600160e01b0319168483015260c08e901b6001600160c01b031916602485015260601b6001600160601b031916602c840152835180840382018152928401845282519281019290922080825260099092529182205482036115c55760408085015163ffffffff16600090815260046020819052828220549251637623ee2960e01b81526001600160401b038f169181019190915290916001600160a01b031690637623ee2990602401602060405180830381865afa158015611500573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061152491906158b7565b905060008190036115775760405162461bcd60e51b815260206004820152601f60248201527f457865637574696f6e20537461746520526f6f74206973206e6f74207365740060448201526064016107e1565b6115ab611584898b6158d0565b60408088015163ffffffff166000908152600560205220546001600160a01b031683612c46565b600083815260096020526040902081905592506115d79050565b60008181526009602052604090205491505b6000846020015160016040516020016116059291906001600160401b03929092168252602082015260400190565b60408051808303601f1901815282825280516020918201208184015281518084038201815292820190915281519101209050600061164d82856116488a8c6158d0565b612d3d565b90508481146116965760405162461bcd60e51b815260206004820152601560248201527424b73b30b634b21036b2b9b9b0b3b2903430b9b41760591b60448201526064016107e1565b505050506116db82828a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612a4092505050565b505061120e6001603355565b6116ff600080516020615e5a83398151915233611898565b61171b5760405162461bcd60e51b81526004016107e190615966565b6000805b600354811015611787578463ffffffff166003828154811061174357611743615937565b6000918252602090912060088204015460079091166004026101000a900463ffffffff16036117755760019150611787565b8061177f816159bb565b91505061171f565b508061181057600380546001810182556000918252600881047fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b01805463ffffffff80891660046007909516949094026101000a84810291021990911617905560405190917f65a791dc0a39717013964ace2b78f8307f275c293b7fdb425346ce8e18cb318891a25b63ffffffff8416600081815260046020908152604080832080546001600160a01b038981166001600160a01b031992831681179093556005855294839020805495891695909116851790558151908152918201929092527f0205eaadbbed4fbe918b2a594d41bceb212a89010cc678c6762b18d65679b2ef910160405180910390a250505050565b600091825260c9602090815260408084206001600160a01b0393909316845291905290205460ff1690565b6118db600080516020615ee183398151915233611898565b6118f75760405162461bcd60e51b81526004016107e1906157a0565b60005b60035463ffffffff8216101561197c5760016006600060038463ffffffff168154811061192957611929615937565b6000918252602080832060088304015460079092166004026101000a90910463ffffffff1683528201929092526040019020805460ff1916911515919091179055806119748161594d565b9150506118fa565b506040517f61340a1b154d5d21d259a74bf95379201799b9d12cc6509bb46cb56dc281df5590600090a1565b6119c0600080516020615ee183398151915233611898565b6119dc5760405162461bcd60e51b81526004016107e1906157a0565b63ffffffff8116600081815260066020526040808220805460ff19166001179055517ff6cf9095f1dcea2429c26c832cbcc084fa0a1692b2c301601edd75b9d83520b29190a250565b60038181548110611a3557600080fd5b9060005260206000209060089182820401919006600402915054906101000a900463ffffffff1681565b6000805460ff16611a825760405162461bcd60e51b81526004016107e19061569d565b468563ffffffff1603611aa75760405162461bcd60e51b81526004016107e1906156ca565b60008061135a87878787611b56565b600082815260c96020526040902060010154611ad181611bcd565b61096a8383611c5d565b611af3600080516020615ee183398151915233611898565b611b0f5760405162461bcd60e51b81526004016107e1906157a0565b6000805460ff19168215159081179091556040519081527f3eea1dc6ce990571e1081137b38c853529a3893b52e9719a48a2f4ac5e3a956c9060200160405180910390a150565b600854600254604080516020601f8601819004810282018101909252848152606093600093611bb99360ff909216926001600160401b0390911691469133918c918c918c908c9081908401838280828437600092019190915250612dd992505050565b805160208201209097909650945050505050565b610ac98133612e14565b611be18282611898565b6109e957600082815260c9602090815260408083206001600160a01b03851684529091529020805460ff19166001179055611c193390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b611c678282611898565b156109e957600082815260c9602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b611cdc600080516020615e5a83398151915233611898565b610ac95760405162461bcd60e51b81526004016107e190615966565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff1615611d2b5761096a83612e6d565b826001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015611d85575060408051601f3d908101601f19168201909252611d82918101906158b7565b60015b611de85760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201526d6f6e206973206e6f74205555505360901b60648201526084016107e1565b600080516020615e9a8339815191528114611e575760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f786044820152681a58589b195555525160ba1b60648201526084016107e1565b5061096a838383612f09565b600260335403611eb55760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016107e1565b6002603355565b6040805160e08101825260008082526020820181905291810182905260608082018390526080820183905260a082019290925260c0810191909152600080611f3985858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612f3492505050565b905060008585604051611f4d9291906159d4565b60405190819003902090506000808281526007602052604090205460ff166002811115611f7c57611f7c615305565b14611fc95760405162461bcd60e51b815260206004820152601960248201527f4d65737361676520616c72656164792065786563757465642e0000000000000060448201526064016107e1565b46826080015163ffffffff16146120115760405162461bcd60e51b815260206004820152600c60248201526b2bb937b7339031b430b4b71760a11b60448201526064016107e1565b600854825160ff90811691161461205b5760405162461bcd60e51b815260206004820152600e60248201526d2bb937b733903b32b939b4b7b71760911b60448201526064016107e1565b60408083015163ffffffff166000908152600460205220546001600160a01b031615806120a6575060408083015163ffffffff166000908152600560205220546001600160a01b0316155b156121195760405162461bcd60e51b815260206004820152603760248201527f4c6967687420636c69656e74206f722062726f616463617374657220666f722060448201527f736f7572636520636861696e206973206e6f742073657400000000000000000060648201526084016107e1565b90925090505b9250929050565b63ffffffff81166000908152600460205260409020546001600160a01b031661218c5760405162461bcd60e51b81526020600482015260186024820152772634b3b43a1031b634b2b73a1034b9903737ba1039b2ba1760411b60448201526064016107e1565b63ffffffff8116600090815260046020818152604092839020548351632bcccca560e01b815293516001600160a01b0390911693632bcccca5938181019392918290030181865afa1580156121e5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061220991906159e4565b610ac95760405162461bcd60e51b815260206004820152601d60248201527f4c6967687420636c69656e7420697320696e636f6e73697374656e742e00000060448201526064016107e1565b63ffffffff811660009081526006602052604090205460ff1615610ac95760405162461bcd60e51b815260206004820152601360248201527221b7b73a3930b1ba1034b990333937bd32b71760691b60448201526064016107e1565b63ffffffff81166000908152600460205260409020546001600160a01b03166123175760405162461bcd60e51b81526020600482015260186024820152772634b3b43a1031b634b2b73a1034b9903737ba1039b2ba1760411b60448201526064016107e1565b63ffffffff8116600090815260046020819052604091829020549151638bc33af360e01b81526001600160401b038516918101919091526001600160a01b0390911690638bc33af390602401602060405180830381865afa158015612380573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123a491906158b7565b6000036123f35760405162461bcd60e51b815260206004820152601e60248201527f54696d657374616d70206973206e6f742073657420666f7220736c6f742e000060448201526064016107e1565b63ffffffff81166000908152600460208190526040808320549051638bc33af360e01b81526001600160401b038616928101929092526001600160a01b031690638bc33af390602401602060405180830381865afa158015612459573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061247d91906158b7565b6124879042615a01565b9050607881101561096a5760405162461bcd60e51b815260206004820152602260248201527f4d7573742077616974206c6f6e67657220746f20757365207468697320736c6f6044820152613a1760f11b60648201526084016107e1565b600080826001600160401b0316846001600160401b0316036125235750600b61251081610200615a14565b61251c90610183615a33565b9050612676565b6120006125308486615a46565b6001600160401b0316116125925750600b61254c816020615a14565b612557906006615a33565b905061256e6120006001600160401b038516615a83565b61257a61200083615a14565b6125849190615a33565b905061251081610200615a14565b836001600160401b0316836001600160401b031610156126245750600b6125ba816020615a14565b6125c5906007615a33565b90506125d2816002615a14565b6125dd906000615a33565b90506125f46120006001600160401b038516615a97565b612602630100000083615a14565b61260c9190615a33565b9050612619816002615a14565b612557906001615a33565b60405162461bcd60e51b815260206004820152602160248201527f54727573746c657373414d423a20696e76616c69642074617267657420736c6f6044820152601d60fa1b60648201526084016107e1565b61268287828888612ff9565b979650505050505050565b60008061269b878a8a613013565b90506000816000815181106126b2576126b2615937565b01602001516001600160f81b03191690506000600160f81b8214806126e45750600160f91b6001600160f81b03198316145b156126f157506001612756565b600360fe1b6001600160f81b031983161061270e57506000612756565b60405162461bcd60e51b815260206004820152601c60248201527f556e737570706f72746564207472616e73616374696f6e20747970650000000060448201526064016107e1565b6000602084019050600060405180604001604052808487516127789190615a01565b81526020016127878585615a33565b905290506000612796826138b3565b905080516004146127e25760405162461bcd60e51b8152602060048201526016602482015275092dcecc2d8d2c840e4cac6cad2e0e840d8cadccee8d60531b60448201526064016107e1565b6000612807826003815181106127fa576127fa615937565b60200260200101516138b3565b905080518c106128595760405162461bcd60e51b815260206004820152601760248201527f4c6f6720696e646578206f7574206f6620626f756e647300000000000000000060448201526064016107e1565b6000612870828e815181106127fa576127fa615937565b905080516003146128ce5760405162461bcd60e51b815260206004820152602260248201527f4c6f672068617320696e636f7272656374206e756d626572206f66206669656c604482015261647360f01b60648201526084016107e1565b60006128f3826000815181106128e6576128e6615937565b6020026020010151613ad8565b90508c6001600160a01b0316816001600160a01b0316146129665760405162461bcd60e51b815260206004820152602760248201527f4576656e7420776173206e6f7420656d697474656420627920636c61696d656460448201526622b6b4ba3a32b960c91b60648201526084016107e1565b600061297e836001815181106127fa576127fa615937565b90508c6129a48260008151811061299757612997615937565b6020026020010151613b42565b14612a075760405162461bcd60e51b815260206004820152602d60248201527f4576656e74207369676e617475726520646f6573206e6f74206d61746368206560448201526c76656e745369676e617475726560981b60648201526084016107e1565b612a29818d81518110612a1c57612a1c615937565b6020026020010151613b49565b9a5050505050505050505050979650505050505050565b600060606000633bdc60d660e01b866040015187606001518860c00151604051602401612a6f93929190615aab565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915260a0870151909150806001600160a01b031682604051612ac19190615adb565b6000604051808303816000865af19150503d8060008114612afe576040519150601f19603f3d011682016040523d82523d6000602084013e612b03565b606091505b5080519195509350600092506020039050612b4557600082806020019051810190612b2e9190615af7565b6001600160e01b031916631dee306b60e11b149150505b828015612b4f5750805b15612b72576000858152600760205260409020805460ff19166002179055612b8c565b6000858152600760205260409020805460ff191660011790555b8486602001516001600160401b0316876040015163ffffffff167f1f26985f3389d5ee1e49b37cdef193b3e98c927d7dd8b6a1f9cddd17a1fe89478787604051612bd7929190615b14565b60405180910390a4505050505050565b6001603355565b603254610100900460ff16612c155760405162461bcd60e51b81526004016107e190615b38565b612c1d613c4c565b565b603254610100900460ff16612c1d5760405162461bcd60e51b81526004016107e190615b38565b6040516001600160601b0319606084901b16602082015260009081906034016040516020818303038152906040528051906020012090506000612cab82604051602001612c9591815260200190565b6040516020818303038152906040528786613013565b90506000815111612cf75760405162461bcd60e51b81526020600482015260166024820152751058d8dbdd5b9d08191bd95cc81b9bdd08195e1a5cdd60521b60448201526064016107e1565b6000612d0a612d0583613c73565b6138b3565b90508051600414612d1a57600080fd5b612d308160028151811061299757612997615937565b93505050505b9392505050565b600080612d6c85604051602001612d5691815260200190565b6040516020818303038152906040528486613013565b90506000815111612dbf5760405162461bcd60e51b815260206004820152601c60248201527f53746f726167652076616c756520646f6573206e6f742065786973740000000060448201526064016107e1565b612dd0612dcb82613c73565b613b42565b95945050505050565b606087878787878787604051602001612df89796959493929190615b83565b6040516020818303038152906040529050979650505050505050565b612e1e8282611898565b6109e957612e2b81613cc6565b612e36836020613cd8565b604051602001612e47929190615c0a565b60408051601f198184030181529082905262461bcd60e51b82526107e19160040161578d565b6001600160a01b0381163b612eda5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b60648201526084016107e1565b600080516020615e9a83398151915280546001600160a01b0319166001600160a01b0392909216919091179055565b612f1283613e73565b600082511180612f1f5750805b1561096a57612f2e8383613eb3565b50505050565b6040805160e08101825260008082526020820181905291810182905260608082018390526080820183905260a082019290925260c081019190915260018201516009830151600d8401516021850151602586015160458088015160ff871688526001600160401b038616602089015263ffffffff80861660408a01526001600160a01b03851660608a01528316608089015260a0880181905288519091612fe8918a9190612fe3908290615a01565b613f9e565b60c088015250949695505050505050565b60008061300786868661408a565b90921495945050505050565b6060600084511161305e5760405162461bcd60e51b81526020600482015260156024820152744d65726b6c65547269653a20656d707479206b657960581b60448201526064016107e1565b600061306984614219565b9050600061307686614307565b905060008460405160200161308d91815260200190565b60405160208183030381529060405290506000805b845181101561385c5760008582815181106130bf576130bf615937565b6020026020010151905084518311156131315760405162461bcd60e51b815260206004820152602e60248201527f4d65726b6c65547269653a206b657920696e646578206578636565647320746f60448201526d0e8c2d840d6caf240d8cadccee8d60931b60648201526084016107e1565b826000036131d0578051805160209182012060405161317f9261315992910190815260200190565b604051602081830303815290604052858051602091820120825192909101919091201490565b6131cb5760405162461bcd60e51b815260206004820152601d60248201527f4d65726b6c65547269653a20696e76616c696420726f6f74206861736800000060448201526064016107e1565b6132c6565b80515160201161325657805180516020918201206040516131fa9261315992910190815260200190565b6131cb5760405162461bcd60e51b815260206004820152602760248201527f4d65726b6c65547269653a20696e76616c6964206c6172676520696e7465726e6044820152660c2d840d0c2e6d60cb1b60648201526084016107e1565b8051845160208087019190912082519190920120146132c65760405162461bcd60e51b815260206004820152602660248201527f4d65726b6c65547269653a20696e76616c696420696e7465726e616c206e6f646044820152650ca40d0c2e6d60d31b60648201526084016107e1565b6132d260106001615a33565b8160200151510361347f578451830361341757600061330e826020015160108151811061330157613301615937565b6020026020010151614421565b905060008151116133875760405162461bcd60e51b815260206004820152603b60248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286272616e636829000000000060648201526084016107e1565b600187516133959190615a01565b83146134095760405162461bcd60e51b815260206004820152603a60248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286272616e63682900000000000060648201526084016107e1565b9650612d3695505050505050565b600085848151811061342b5761342b615937565b602001015160f81c60f81b60f81c9050600082602001518260ff168151811061345657613456615937565b6020026020010151905061346981614544565b9550613476600186615a33565b94505050613849565b6002816020015151036137f057600061349782614569565b90506000816000815181106134ae576134ae615937565b016020015160f81c905060006134c5600283615c7f565b6134d0906002615ca1565b905060006134e1848360ff1661458d565b905060006134ef8a8961458d565b905060006134fd83836145c3565b9050808351146135755760405162461bcd60e51b815260206004820152603a60248201527f4d65726b6c65547269653a20706174682072656d61696e646572206d7573742060448201527f736861726520616c6c206e6962626c65732077697468206b657900000000000060648201526084016107e1565b60ff85166002148061358a575060ff85166003145b1561373057808251146136055760405162461bcd60e51b815260206004820152603d60248201527f4d65726b6c65547269653a206b65792072656d61696e646572206d757374206260448201527f65206964656e746963616c20746f20706174682072656d61696e64657200000060648201526084016107e1565b6000613621886020015160018151811061330157613301615937565b9050600081511161369a5760405162461bcd60e51b815260206004820152603960248201527f4d65726b6c65547269653a2076616c7565206c656e677468206d75737420626560448201527f2067726561746572207468616e207a65726f20286c656166290000000000000060648201526084016107e1565b60018d516136a89190615a01565b891461371c5760405162461bcd60e51b815260206004820152603860248201527f4d65726b6c65547269653a2076616c7565206e6f6465206d757374206265206c60448201527f617374206e6f646520696e2070726f6f6620286c65616629000000000000000060648201526084016107e1565b9c50612d369b505050505050505050505050565b60ff85161580613743575060ff85166001145b156137825761376f876020015160018151811061376257613762615937565b6020026020010151614544565b995061377b818a615a33565b98506137e5565b60405162461bcd60e51b815260206004820152603260248201527f4d65726b6c65547269653a2072656365697665642061206e6f64652077697468604482015271040c2dc40eadcd6dcdeeedc40e0e4caccd2f60731b60648201526084016107e1565b505050505050613849565b60405162461bcd60e51b815260206004820152602860248201527f4d65726b6c65547269653a20726563656976656420616e20756e706172736561604482015267626c65206e6f646560c01b60648201526084016107e1565b5080613854816159bb565b9150506130a2565b5060405162461bcd60e51b815260206004820152602560248201527f4d65726b6c65547269653a2072616e206f7574206f662070726f6f6620656c656044820152646d656e747360d81b60648201526084016107e1565b606060008060006138c385614642565b9194509250905060018160018111156138de576138de615305565b146139515760405162461bcd60e51b815260206004820152603860248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206c697374206973206e6f742061206c697374206974656d000000000000000060648201526084016107e1565b845161395d8385615a33565b146139c55760405162461bcd60e51b815260206004820152603260248201527f524c505265616465723a206c697374206974656d2068617320616e20696e76616044820152713634b2103230ba30903932b6b0b4b73232b960711b60648201526084016107e1565b6040805160208082526104208201909252600091816020015b60408051808201909152600080825260208201528152602001906001900390816139de5790505090506000845b8751811015613acc57600080613a516040518060400160405280858d60000151613a359190615a01565b8152602001858d60200151613a4a9190615a33565b9052614642565b509150915060405180604001604052808383613a6d9190615a33565b8152602001848c60200151613a829190615a33565b815250858581518110613a9757613a97615937565b6020908102919091010152613aad600185615a33565b9350613ab98183615a33565b613ac39084615a33565b92505050613a0b565b50815295945050505050565b8051600090600103613aec57506000919050565b8151601514613b3d5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020616464726573732076616c75652e00000000000060448201526064016107e1565b6107b8825b60006107b8825b6000602182600001511115613ba05760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e00000000000060448201526064016107e1565b6000806000613bae85614642565b919450925090506000816001811115613bc957613bc9615305565b14613c165760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e00000000000060448201526064016107e1565b6000838660200151613c289190615a33565b80519091506020841015613c425760208490036101000a90045b9695505050505050565b603254610100900460ff16612be75760405162461bcd60e51b81526004016107e190615b38565b60408051808201909152600080825260208201526000825111613ca85760405162461bcd60e51b81526004016107e190615cba565b50604080518082019091528151815260209182019181019190915290565b60606107b86001600160a01b03831660145b60606000613ce7836002615a14565b613cf2906002615a33565b6001600160401b03811115613d0957613d09615153565b6040519080825280601f01601f191660200182016040528015613d33576020820181803683370190505b509050600360fc1b81600081518110613d4e57613d4e615937565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110613d7d57613d7d615937565b60200101906001600160f81b031916908160001a9053506000613da1846002615a14565b613dac906001615a33565b90505b6001811115613e24576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110613de057613de0615937565b1a60f81b828281518110613df657613df6615937565b60200101906001600160f81b031916908160001a90535060049490941c93613e1d81615d2a565b9050613daf565b508315612d365760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e7460448201526064016107e1565b613e7c81612e6d565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60606001600160a01b0383163b613f1b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a2064656c65676174652063616c6c20746f206e6f6e2d636f6044820152651b9d1c9858dd60d21b60648201526084016107e1565b600080846001600160a01b031684604051613f369190615adb565b600060405180830381855af49150503d8060008114613f71576040519150601f19603f3d011682016040523d82523d6000602084013e613f76565b606091505b5091509150612dd08282604051806060016040528060278152602001615eba60279139614d05565b606081613fac81601f615a33565b1015613fca5760405162461bcd60e51b81526004016107e190615d41565b613fd48284615a33565b845110156140185760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b60448201526064016107e1565b6060821580156140375760405191506000825260208201604052614081565b6040519150601f8416801560200281840101858101878315602002848b0101015b81831015614070578051835260209283019201614058565b5050858452601f01601f1916604052505b50949350505050565b6000828251600161409b9190615a33565b6140a6906002615e4d565b116140b057600080fd5b8360005b84600114614081576140c7600286615a83565b6001036141665760028482815181106140e2576140e2615937565b602002602001015183604051602001614105929190918252602082015260400190565b60408051601f198184030181529082905261411f91615adb565b602060405180830381855afa15801561413c573d6000803e3d6000fd5b5050506040513d601f19601f8201168201806040525081019061415f91906158b7565b91506141fa565b60028285838151811061417b5761417b615937565b602002602001015160405160200161419d929190918252602082015260400190565b60408051601f19818403018152908290526141b791615adb565b602060405180830381855afa1580156141d4573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906141f791906158b7565b91505b614205600286615a97565b945080614211816159bb565b9150506140b4565b80516060906000816001600160401b0381111561423857614238615153565b60405190808252806020026020018201604052801561427d57816020015b60408051808201909152606080825260208201528152602001906001900390816142565790505b50905060005b828110156142ff5760405180604001604052808683815181106142a8576142a8615937565b602002602001015181526020016142d78784815181106142ca576142ca615937565b6020026020010151614d1e565b8152508282815181106142ec576142ec615937565b6020908102919091010152600101614283565b509392505050565b80516060906000614319826002615a14565b6001600160401b0381111561433057614330615153565b6040519080825280601f01601f19166020018201604052801561435a576020820181803683370190505b5090506000805b838110156144175785818151811061437b5761437b615937565b6020910101516001600160f81b03198116925060041c60ff60f41b16836143a3836002615a14565b815181106143b3576143b3615937565b60200101906001600160f81b031916908160001a905350600f60f81b8216836143dd836002615a14565b6143e8906001615a33565b815181106143f8576143f8615937565b60200101906001600160f81b031916908160001a905350600101614361565b5090949350505050565b6060600080600061443185614642565b91945092509050600081600181111561444c5761444c615305565b146144bf5760405162461bcd60e51b815260206004820152603960248201527f524c505265616465723a206465636f646564206974656d207479706520666f7260448201527f206279746573206973206e6f7420612064617461206974656d0000000000000060648201526084016107e1565b6144c98284615a33565b8551146145355760405162461bcd60e51b815260206004820152603460248201527f524c505265616465723a2062797465732076616c756520636f6e7461696e732060448201527330b71034b73b30b634b2103932b6b0b4b73232b960611b60648201526084016107e1565b612dd085602001518484614d2c565b606060208260000151106145605761455b82614421565b6107b8565b6107b882614dcc565b60606107b8614588836020015160008151811061330157613301615937565b614307565b6060825182106145ac57506040805160208101909152600081526107b8565b612d3683838486516145be9190615a01565b614de2565b600080600083518551106145d85783516145db565b84515b90505b808210801561463257508382815181106145fa576145fa615937565b602001015160f81c60f81b6001600160f81b03191685838151811061462157614621615937565b01602001516001600160f81b031916145b156142ff578160010191506145de565b60008060008084600001511161466a5760405162461bcd60e51b81526004016107e190615cba565b6020840151805160001a607f811161468f576000600160009450945094505050614cfe565b60b781116147ec5760006146a4608083615a01565b9050808760000151116147245760405162461bcd60e51b815260206004820152604e6024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e20737472696e67206c656e6774682060648201526d2873686f727420737472696e672960901b608482015260a4016107e1565b6001838101516001600160f81b03191690821415806147515750600160ff1b6001600160f81b0319821610155b6147d95760405162461bcd60e51b815260206004820152604d60248201527f524c505265616465723a20696e76616c6964207072656669782c2073696e676c60448201527f652062797465203c203078383020617265206e6f74207072656669786564202860648201526c73686f727420737472696e672960981b608482015260a4016107e1565b5060019550935060009250614cfe915050565b60bf8111614a2d57600061480160b783615a01565b9050808760000151116148845760405162461bcd60e51b81526020600482015260516024820152600080516020615e7a83398151915260448201527f74206265203e207468616e206c656e677468206f6620737472696e67206c656e60648201527067746820286c6f6e6720737472696e672960781b608482015260a4016107e1565b60018301516001600160f81b031916600081900361490b5760405162461bcd60e51b815260206004820152604a6024820152600080516020615e7a83398151915260448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f6064820152696e6720737472696e672960b01b608482015260a4016107e1565b600184015160088302610100031c6037811161498e5760405162461bcd60e51b81526020600482015260486024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e20353520627974657320286c6f6e6760648201526720737472696e672960c01b608482015260a4016107e1565b6149988184615a33565b895111614a105760405162461bcd60e51b815260206004820152604c6024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e20746f74616c206c656e677468202860648201526b6c6f6e6720737472696e672960a01b608482015260a4016107e1565b614a1b836001615a33565b9750955060009450614cfe9350505050565b60f78111614acf576000614a4260c083615a01565b905080876000015111614abe5760405162461bcd60e51b815260206004820152604a6024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e206c697374206c656e677468202873606482015269686f7274206c6973742960b01b608482015260a4016107e1565b600195509350849250614cfe915050565b6000614adc60f783615a01565b905080876000015111614b5b5760405162461bcd60e51b815260206004820152604d6024820152600080516020615e7a83398151915260448201527f74206265203e207468616e206c656e677468206f66206c697374206c656e677460648201526c6820286c6f6e67206c6973742960981b608482015260a4016107e1565b60018301516001600160f81b0319166000819003614be05760405162461bcd60e51b81526020600482015260486024820152600080516020615e7a83398151915260448201527f74206e6f74206861766520616e79206c656164696e67207a65726f7320286c6f6064820152676e67206c6973742960c01b608482015260a4016107e1565b600184015160088302610100031c60378111614c615760405162461bcd60e51b81526020600482015260466024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e20353520627974657320286c6f6e67606482015265206c6973742960d01b608482015260a4016107e1565b614c6b8184615a33565b895111614ce15760405162461bcd60e51b815260206004820152604a6024820152600080516020615e7a83398151915260448201527f742062652067726561746572207468616e20746f74616c206c656e67746820286064820152696c6f6e67206c6973742960b01b608482015260a4016107e1565b614cec836001615a33565b9750955060019450614cfe9350505050565b9193909250565b60608315614d14575081612d36565b612d368383614e70565b60606107b8612d0583613c73565b60606000826001600160401b03811115614d4857614d48615153565b6040519080825280601f01601f191660200182016040528015614d72576020820181803683370190505b50905082600003614d84579050612d36565b6000614d908587615a33565b90506020820160005b85811015614db1578281015182820152602001614d99565b85811115614dc0576000868301525b50919695505050505050565b60606107b8826020015160008460000151614d2c565b60608182601f011015614e075760405162461bcd60e51b81526004016107e190615d41565b828284011015614e295760405162461bcd60e51b81526004016107e190615d41565b818301845110156140185760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b60448201526064016107e1565b815115614e805781518083602001fd5b8060405162461bcd60e51b81526004016107e1919061578d565b82805482825590600052602060002090600701600890048101928215614f395791602002820160005b83821115614f0757835183826101000a81548163ffffffff021916908363ffffffff1602179055509260200192600401602081600301049283019260010302614ec3565b8015614f375782816101000a81549063ffffffff0219169055600401602081600301049283019260010302614f07565b505b50614f45929150614f49565b5090565b5b80821115614f455760008155600101614f4a565b6001600160e01b031981168114610ac957600080fd5b600060208284031215614f8657600080fd5b8135612d3681614f5e565b80356001600160401b0381168114614fa857600080fd5b919050565b600060208284031215614fbf57600080fd5b612d3682614f91565b803563ffffffff81168114614fa857600080fd5b80356001600160a01b0381168114614fa857600080fd5b60008083601f84011261500557600080fd5b5081356001600160401b0381111561501c57600080fd5b60208301915083602082850101111561211f57600080fd5b6000806000806060858703121561504a57600080fd5b61505385614fc8565b935061506160208601614fdc565b925060408501356001600160401b0381111561507c57600080fd5b61508887828801614ff3565b95989497509550505050565b6000602082840312156150a657600080fd5b612d3682614fc8565b6000602082840312156150c157600080fd5b5035919050565b600080604083850312156150db57600080fd5b823591506150eb60208401614fdc565b90509250929050565b60006020828403121561510657600080fd5b612d3682614fdc565b60008083601f84011261512157600080fd5b5081356001600160401b0381111561513857600080fd5b6020830191508360208260051b850101111561211f57600080fd5b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561519157615191615153565b604052919050565b600082601f8301126151aa57600080fd5b81356001600160401b038111156151c3576151c3615153565b6151d6601f8201601f1916602001615169565b8181528460208386010111156151eb57600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600080600080600080600060e08c8e03121561522957600080fd5b6001600160401b03808d35111561523f57600080fd5b61524c8e8e358f01614ff3565b909c509a5060208d013581101561526257600080fd5b6152728e60208f01358f01614ff3565b909a50985060408d013581101561528857600080fd5b6152988e60408f01358f0161510f565b909850965060608d0135955060808d01358110156152b557600080fd5b6152c58e60808f01358f0161510f565b909550935060a08d01358110156152db57600080fd5b506152ec8d60a08e01358e01615199565b915060c08c013590509295989b509295989b9093969950565b634e487b7160e01b600052602160045260246000fd5b602081016003831061533d57634e487b7160e01b600052602160045260246000fd5b91905290565b6000806040838503121561535657600080fd5b61535f83614fdc565b915060208301356001600160401b0381111561537a57600080fd5b61538685828601615199565b9150509250929050565b60006001600160401b038211156153a9576153a9615153565b5060051b60200190565b600082601f8301126153c457600080fd5b813560206153d96153d483615390565b615169565b82815260059290921b840181019181810190868411156153f857600080fd5b8286015b8481101561541a5761540d81614fdc565b83529183019183016153fc565b509695505050505050565b8015158114610ac957600080fd5b8035614fa881615425565b60008060008060008060c0878903121561545757600080fd5b86356001600160401b038082111561546e57600080fd5b818901915089601f83011261548257600080fd5b813560206154926153d483615390565b82815260059290921b8401810191818101908d8411156154b157600080fd5b948201945b838610156154d6576154c786614fc8565b825294820194908201906154b6565b9a50508a0135925050808211156154ec57600080fd5b6154f88a838b016153b3565b9650604089013591508082111561550e57600080fd5b5061551b89828a016153b3565b94505061552a60608801614fdc565b925061553860808801614fdc565b915061554660a08801615433565b90509295509295509295565b6000806000806060858703121561556857600080fd5b61557185614fc8565b93506020850135925060408501356001600160401b0381111561507c57600080fd5b60008060008060008060006080888a0312156155ae57600080fd5b6155b788614f91565b965060208801356001600160401b03808211156155d357600080fd5b6155df8b838c01614ff3565b909850965060408a01359150808211156155f857600080fd5b6156048b838c0161510f565b909650945060608a013591508082111561561d57600080fd5b5061562a8a828b0161510f565b989b979a50959850939692959293505050565b60008060006060848603121561565257600080fd5b61565b84614fc8565b925061566960208501614fdc565b915061567760408501614fdc565b90509250925092565b60006020828403121561569257600080fd5b8135612d3681615425565b60208082526013908201527214d95b991a5b99c81a5cc8191a5cd8589b1959606a1b604082015260600190565b60208082526019908201527f43616e6e6f742073656e6420746f2073616d6520636861696e00000000000000604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60006001600160401b0380831681810361573357615733615701565b6001019392505050565b60005b83811015615758578181015183820152602001615740565b50506000910152565b6000815180845261577981602086016020860161573d565b601f01601f19169290920160200192915050565b602081526000612d366020830184615761565b60208082526035908201527f54656c657061746879526f757465723a206f6e6c7920677561726469616e206360408201527430b71031b0b636103a3434b990333ab731ba34b7b760591b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b19195b1959d85d1958d85b1b60a21b606082015260800190565b6020808252602c908201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060408201526b6163746976652070726f787960a01b606082015260800190565b600080604083850312156158a057600080fd5b6158a983614f91565b91506150eb60208401614f91565b6000602082840312156158c957600080fd5b5051919050565b60006158de6153d484615390565b80848252602080830192508560051b8501368111156158fc57600080fd5b855b81811015614dc05780356001600160401b0381111561591d5760008081fd5b61592936828a01615199565b8652509382019382016158fe565b634e487b7160e01b600052603260045260246000fd5b600063ffffffff80831681810361573357615733615701565b60208082526035908201527f54656c657061746879526f757465723a206f6e6c792074696d656c6f636b206360408201527430b71031b0b636103a3434b990333ab731ba34b7b760591b606082015260800190565b6000600182016159cd576159cd615701565b5060010190565b8183823760009101908152919050565b6000602082840312156159f657600080fd5b8151612d3681615425565b818103818111156107b8576107b8615701565b6000816000190483118215151615615a2e57615a2e615701565b500290565b808201808211156107b8576107b8615701565b6001600160401b03828116828216039080821115615a6657615a66615701565b5092915050565b634e487b7160e01b600052601260045260246000fd5b600082615a9257615a92615a6d565b500690565b600082615aa657615aa6615a6d565b500490565b63ffffffff841681526001600160a01b0383166020820152606060408201819052600090612dd090830184615761565b60008251615aed81846020870161573d565b9190910192915050565b600060208284031215615b0957600080fd5b8151612d3681614f5e565b604081526000615b276040830185615761565b905082151560208301529392505050565b6020808252602b908201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960408201526a6e697469616c697a696e6760a81b606082015260800190565b6001600160f81b031960f889901b1681526001600160c01b031960c088901b1660018201526001600160e01b031960e087811b821660098401526001600160601b0319606088901b16600d84015285901b166021820152602581018390528151600090615bf781604585016020870161573d565b9190910160450198975050505050505050565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351615c4281601785016020880161573d565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351615c7381602884016020880161573d565b01602801949350505050565b600060ff831680615c9257615c92615a6d565b8060ff84160691505092915050565b60ff82811682821603908111156107b8576107b8615701565b6020808252604a908201527f524c505265616465723a206c656e677468206f6620616e20524c50206974656d60408201527f206d7573742062652067726561746572207468616e207a65726f20746f206265606082015269206465636f6461626c6560b01b608082015260a00190565b600081615d3957615d39615701565b506000190190565b6020808252600e908201526d736c6963655f6f766572666c6f7760901b604082015260600190565b600181815b80851115615da4578160001904821115615d8a57615d8a615701565b80851615615d9757918102915b93841c9390800290615d6e565b509250929050565b600082615dbb575060016107b8565b81615dc8575060006107b8565b8160018114615dde5760028114615de857615e04565b60019150506107b8565b60ff841115615df957615df9615701565b50506001821b6107b8565b5060208310610133831016604e8410600b8410161715615e27575081810a6107b8565b615e318383615d69565b8060001904821115615e4557615e45615701565b029392505050565b6000612d368383615dac56fef66846415d2bf9eabda9e84793ff9c0ea96d87f50fc41e66aa16469c6a442f05524c505265616465723a206c656e677468206f6620636f6e74656e74206d7573360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c656455435dd261a4b9b3364963f7738a7a662ad9c84396d64be3365284bb7f0a5041a2646970667358221220f69b1c44e29eed792424bef643e588366626efef00e60b2c59813e1a349096ed64736f6c63430008100033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.