Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
This contract has been partially verified via Sourcify.
- Contract name:
- ReceiveUln302
- Optimization enabled
- true
- Compiler version
- v0.8.22+commit.4fc1097e
- Optimization runs
- 20000
- EVM Version
- paris
- Verified at
- 2024-09-20T12:14:55.148384Z
Constructor Arguments
0x0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b
Arg [0] (address) : 0x6f475642a6e85809b1c36fa62763669b1b48dd5b
contracts/uln/uln302/ReceiveUln302.sol
// SPDX-License-Identifier: LZBL-1.2 pragma solidity ^0.8.20; import { PacketV1Codec } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol"; import { SetConfigParam } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessageLibManager.sol"; import { ILayerZeroEndpointV2, Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol"; import { IReceiveUlnE2 } from "../interfaces/IReceiveUlnE2.sol"; import { ReceiveUlnBase } from "../ReceiveUlnBase.sol"; import { ReceiveLibBaseE2 } from "../../ReceiveLibBaseE2.sol"; import { UlnConfig } from "../UlnBase.sol"; /// @dev This is a gluing contract. It simply parses the requests and forward to the super.impl() accordingly. /// @dev In this case, it combines the logic of ReceiveUlnBase and ReceiveLibBaseE2 contract ReceiveUln302 is IReceiveUlnE2, ReceiveUlnBase, ReceiveLibBaseE2 { using PacketV1Codec for bytes; /// @dev CONFIG_TYPE_ULN=2 here to align with SendUln302/ReceiveUln302/ReceiveUln301 uint32 internal constant CONFIG_TYPE_ULN = 2; error LZ_ULN_InvalidConfigType(uint32 configType); constructor(address _endpoint) ReceiveLibBaseE2(_endpoint) {} function supportsInterface(bytes4 _interfaceId) public view override returns (bool) { return _interfaceId == type(IReceiveUlnE2).interfaceId || super.supportsInterface(_interfaceId); } // ============================ OnlyEndpoint =================================== // only the ULN config on the receive side function setConfig(address _oapp, SetConfigParam[] calldata _params) external override onlyEndpoint { for (uint256 i = 0; i < _params.length; i++) { SetConfigParam calldata param = _params[i]; _assertSupportedEid(param.eid); if (param.configType == CONFIG_TYPE_ULN) { _setUlnConfig(param.eid, _oapp, abi.decode(param.config, (UlnConfig))); } else { revert LZ_ULN_InvalidConfigType(param.configType); } } } // ============================ External =================================== /// @dev dont need to check endpoint verifiable here to save gas, as it will reverts if not verifiable. function commitVerification(bytes calldata _packetHeader, bytes32 _payloadHash) external { _assertHeader(_packetHeader, localEid); // cache these values to save gas address receiver = _packetHeader.receiverB20(); uint32 srcEid = _packetHeader.srcEid(); UlnConfig memory config = getUlnConfig(receiver, srcEid); _verifyAndReclaimStorage(config, keccak256(_packetHeader), _payloadHash); Origin memory origin = Origin(srcEid, _packetHeader.sender(), _packetHeader.nonce()); // endpoint will revert if nonce <= lazyInboundNonce ILayerZeroEndpointV2(endpoint).verify(origin, receiver, _payloadHash); } /// @dev for dvn to verify the payload function verify(bytes calldata _packetHeader, bytes32 _payloadHash, uint64 _confirmations) external { _verify(_packetHeader, _payloadHash, _confirmations); } // ============================ View =================================== function getConfig(uint32 _eid, address _oapp, uint32 _configType) external view override returns (bytes memory) { if (_configType == CONFIG_TYPE_ULN) { return abi.encode(getUlnConfig(_oapp, _eid)); } else { revert LZ_ULN_InvalidConfigType(_configType); } } function isSupportedEid(uint32 _eid) external view override returns (bool) { return _isSupportedEid(_eid); } function version() external pure override returns (uint64 major, uint8 minor, uint8 endpointVersion) { return (3, 0, 2); } }
@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import { IMessageLibManager } from "./IMessageLibManager.sol"; import { IMessagingComposer } from "./IMessagingComposer.sol"; import { IMessagingChannel } from "./IMessagingChannel.sol"; import { IMessagingContext } from "./IMessagingContext.sol"; struct MessagingParams { uint32 dstEid; bytes32 receiver; bytes message; bytes options; bool payInLzToken; } struct MessagingReceipt { bytes32 guid; uint64 nonce; MessagingFee fee; } struct MessagingFee { uint256 nativeFee; uint256 lzTokenFee; } struct Origin { uint32 srcEid; bytes32 sender; uint64 nonce; } interface ILayerZeroEndpointV2 is IMessageLibManager, IMessagingComposer, IMessagingChannel, IMessagingContext { event PacketSent(bytes encodedPayload, bytes options, address sendLibrary); event PacketVerified(Origin origin, address receiver, bytes32 payloadHash); event PacketDelivered(Origin origin, address receiver); event LzReceiveAlert( address indexed receiver, address indexed executor, Origin origin, bytes32 guid, uint256 gas, uint256 value, bytes message, bytes extraData, bytes reason ); event LzTokenSet(address token); event DelegateSet(address sender, address delegate); function quote(MessagingParams calldata _params, address _sender) external view returns (MessagingFee memory); function send( MessagingParams calldata _params, address _refundAddress ) external payable returns (MessagingReceipt memory); function verify(Origin calldata _origin, address _receiver, bytes32 _payloadHash) external; function verifiable(Origin calldata _origin, address _receiver) external view returns (bool); function initializable(Origin calldata _origin, address _receiver) external view returns (bool); function lzReceive( Origin calldata _origin, address _receiver, bytes32 _guid, bytes calldata _message, bytes calldata _extraData ) external payable; // oapp can burn messages partially by calling this function with its own business logic if messages are verified in order function clear(address _oapp, Origin calldata _origin, bytes32 _guid, bytes calldata _message) external; function setLzToken(address _lzToken) external; function lzToken() external view returns (address); function nativeToken() external view returns (address); function setDelegate(address _delegate) external; }
@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessageLib.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import { SetConfigParam } from "./IMessageLibManager.sol"; enum MessageLibType { Send, Receive, SendAndReceive } interface IMessageLib is IERC165 { function setConfig(address _oapp, SetConfigParam[] calldata _config) external; function getConfig(uint32 _eid, address _oapp, uint32 _configType) external view returns (bytes memory config); function isSupportedEid(uint32 _eid) external view returns (bool); // message libs of same major version are compatible function version() external view returns (uint64 major, uint8 minor, uint8 endpointVersion); function messageLibType() external view returns (MessageLibType); }
@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessageLibManager.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; struct SetConfigParam { uint32 eid; uint32 configType; bytes config; } interface IMessageLibManager { struct Timeout { address lib; uint256 expiry; } event LibraryRegistered(address newLib); event DefaultSendLibrarySet(uint32 eid, address newLib); event DefaultReceiveLibrarySet(uint32 eid, address newLib); event DefaultReceiveLibraryTimeoutSet(uint32 eid, address oldLib, uint256 expiry); event SendLibrarySet(address sender, uint32 eid, address newLib); event ReceiveLibrarySet(address receiver, uint32 eid, address newLib); event ReceiveLibraryTimeoutSet(address receiver, uint32 eid, address oldLib, uint256 timeout); function registerLibrary(address _lib) external; function isRegisteredLibrary(address _lib) external view returns (bool); function getRegisteredLibraries() external view returns (address[] memory); function setDefaultSendLibrary(uint32 _eid, address _newLib) external; function defaultSendLibrary(uint32 _eid) external view returns (address); function setDefaultReceiveLibrary(uint32 _eid, address _newLib, uint256 _gracePeriod) external; function defaultReceiveLibrary(uint32 _eid) external view returns (address); function setDefaultReceiveLibraryTimeout(uint32 _eid, address _lib, uint256 _expiry) external; function defaultReceiveLibraryTimeout(uint32 _eid) external view returns (address lib, uint256 expiry); function isSupportedEid(uint32 _eid) external view returns (bool); function isValidReceiveLibrary(address _receiver, uint32 _eid, address _lib) external view returns (bool); /// ------------------- OApp interfaces ------------------- function setSendLibrary(address _oapp, uint32 _eid, address _newLib) external; function getSendLibrary(address _sender, uint32 _eid) external view returns (address lib); function isDefaultSendLibrary(address _sender, uint32 _eid) external view returns (bool); function setReceiveLibrary(address _oapp, uint32 _eid, address _newLib, uint256 _gracePeriod) external; function getReceiveLibrary(address _receiver, uint32 _eid) external view returns (address lib, bool isDefault); function setReceiveLibraryTimeout(address _oapp, uint32 _eid, address _lib, uint256 _expiry) external; function receiveLibraryTimeout(address _receiver, uint32 _eid) external view returns (address lib, uint256 expiry); function setConfig(address _oapp, address _lib, SetConfigParam[] calldata _params) external; function getConfig( address _oapp, address _lib, uint32 _eid, uint32 _configType ) external view returns (bytes memory config); }
@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessagingChannel.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; interface IMessagingChannel { event InboundNonceSkipped(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce); event PacketNilified(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash); event PacketBurnt(uint32 srcEid, bytes32 sender, address receiver, uint64 nonce, bytes32 payloadHash); function eid() external view returns (uint32); // this is an emergency function if a message cannot be verified for some reasons // required to provide _nextNonce to avoid race condition function skip(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce) external; function nilify(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external; function burn(address _oapp, uint32 _srcEid, bytes32 _sender, uint64 _nonce, bytes32 _payloadHash) external; function nextGuid(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (bytes32); function inboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64); function outboundNonce(address _sender, uint32 _dstEid, bytes32 _receiver) external view returns (uint64); function inboundPayloadHash( address _receiver, uint32 _srcEid, bytes32 _sender, uint64 _nonce ) external view returns (bytes32); function lazyInboundNonce(address _receiver, uint32 _srcEid, bytes32 _sender) external view returns (uint64); }
@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessagingComposer.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; interface IMessagingComposer { event ComposeSent(address from, address to, bytes32 guid, uint16 index, bytes message); event ComposeDelivered(address from, address to, bytes32 guid, uint16 index); event LzComposeAlert( address indexed from, address indexed to, address indexed executor, bytes32 guid, uint16 index, uint256 gas, uint256 value, bytes message, bytes extraData, bytes reason ); function composeQueue( address _from, address _to, bytes32 _guid, uint16 _index ) external view returns (bytes32 messageHash); function sendCompose(address _to, bytes32 _guid, uint16 _index, bytes calldata _message) external; function lzCompose( address _from, address _to, bytes32 _guid, uint16 _index, bytes calldata _message, bytes calldata _extraData ) external payable; }
@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessagingContext.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; interface IMessagingContext { function isSendingMessage() external view returns (bool); function getSendContext() external view returns (uint32 dstEid, address sender); }
@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ISendLib.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; import { MessagingFee } from "./ILayerZeroEndpointV2.sol"; import { IMessageLib } from "./IMessageLib.sol"; struct Packet { uint64 nonce; uint32 srcEid; address sender; uint32 dstEid; bytes32 receiver; bytes32 guid; bytes message; } interface ISendLib is IMessageLib { function send( Packet calldata _packet, bytes calldata _options, bool _payInLzToken ) external returns (MessagingFee memory, bytes memory encodedPacket); function quote( Packet calldata _packet, bytes calldata _options, bool _payInLzToken ) external view returns (MessagingFee memory); function setTreasury(address _treasury) external; function withdrawFee(address _to, uint256 _amount) external; function withdrawLzTokenFee(address _lzToken, address _to, uint256 _amount) external; }
@layerzerolabs/lz-evm-protocol-v2/contracts/libs/AddressCast.sol
// SPDX-License-Identifier: LZBL-1.2 pragma solidity ^0.8.20; library AddressCast { error AddressCast_InvalidSizeForAddress(); error AddressCast_InvalidAddress(); function toBytes32(bytes calldata _addressBytes) internal pure returns (bytes32 result) { if (_addressBytes.length > 32) revert AddressCast_InvalidAddress(); result = bytes32(_addressBytes); unchecked { uint256 offset = 32 - _addressBytes.length; result = result >> (offset * 8); } } function toBytes32(address _address) internal pure returns (bytes32 result) { result = bytes32(uint256(uint160(_address))); } function toBytes(bytes32 _addressBytes32, uint256 _size) internal pure returns (bytes memory result) { if (_size == 0 || _size > 32) revert AddressCast_InvalidSizeForAddress(); result = new bytes(_size); unchecked { uint256 offset = 256 - _size * 8; assembly { mstore(add(result, 32), shl(offset, _addressBytes32)) } } } function toAddress(bytes32 _addressBytes32) internal pure returns (address result) { result = address(uint160(uint256(_addressBytes32))); } function toAddress(bytes calldata _addressBytes) internal pure returns (address result) { if (_addressBytes.length != 20) revert AddressCast_InvalidAddress(); result = address(bytes20(_addressBytes)); } }
@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol
// SPDX-License-Identifier: LZBL-1.2 pragma solidity ^0.8.20; import { Packet } from "../../interfaces/ISendLib.sol"; import { AddressCast } from "../../libs/AddressCast.sol"; library PacketV1Codec { using AddressCast for address; using AddressCast for bytes32; uint8 internal constant PACKET_VERSION = 1; // header (version + nonce + path) // version uint256 private constant PACKET_VERSION_OFFSET = 0; // nonce uint256 private constant NONCE_OFFSET = 1; // path uint256 private constant SRC_EID_OFFSET = 9; uint256 private constant SENDER_OFFSET = 13; uint256 private constant DST_EID_OFFSET = 45; uint256 private constant RECEIVER_OFFSET = 49; // payload (guid + message) uint256 private constant GUID_OFFSET = 81; // keccak256(nonce + path) uint256 private constant MESSAGE_OFFSET = 113; function encode(Packet memory _packet) internal pure returns (bytes memory encodedPacket) { encodedPacket = abi.encodePacked( PACKET_VERSION, _packet.nonce, _packet.srcEid, _packet.sender.toBytes32(), _packet.dstEid, _packet.receiver, _packet.guid, _packet.message ); } function encodePacketHeader(Packet memory _packet) internal pure returns (bytes memory) { return abi.encodePacked( PACKET_VERSION, _packet.nonce, _packet.srcEid, _packet.sender.toBytes32(), _packet.dstEid, _packet.receiver ); } function encodePayload(Packet memory _packet) internal pure returns (bytes memory) { return abi.encodePacked(_packet.guid, _packet.message); } function header(bytes calldata _packet) internal pure returns (bytes calldata) { return _packet[0:GUID_OFFSET]; } function version(bytes calldata _packet) internal pure returns (uint8) { return uint8(bytes1(_packet[PACKET_VERSION_OFFSET:NONCE_OFFSET])); } function nonce(bytes calldata _packet) internal pure returns (uint64) { return uint64(bytes8(_packet[NONCE_OFFSET:SRC_EID_OFFSET])); } function srcEid(bytes calldata _packet) internal pure returns (uint32) { return uint32(bytes4(_packet[SRC_EID_OFFSET:SENDER_OFFSET])); } function sender(bytes calldata _packet) internal pure returns (bytes32) { return bytes32(_packet[SENDER_OFFSET:DST_EID_OFFSET]); } function senderAddressB20(bytes calldata _packet) internal pure returns (address) { return sender(_packet).toAddress(); } function dstEid(bytes calldata _packet) internal pure returns (uint32) { return uint32(bytes4(_packet[DST_EID_OFFSET:RECEIVER_OFFSET])); } function receiver(bytes calldata _packet) internal pure returns (bytes32) { return bytes32(_packet[RECEIVER_OFFSET:GUID_OFFSET]); } function receiverB20(bytes calldata _packet) internal pure returns (address) { return receiver(_packet).toAddress(); } function guid(bytes calldata _packet) internal pure returns (bytes32) { return bytes32(_packet[GUID_OFFSET:MESSAGE_OFFSET]); } function message(bytes calldata _packet) internal pure returns (bytes calldata) { return bytes(_packet[MESSAGE_OFFSET:]); } function payload(bytes calldata _packet) internal pure returns (bytes calldata) { return bytes(_packet[GUID_OFFSET:]); } function payloadHash(bytes calldata _packet) internal pure returns (bytes32) { return keccak256(payload(_packet)); } }
@openzeppelin/contracts/access/Ownable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * 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 Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _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. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { 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); } }
@openzeppelin/contracts/utils/Context.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
@openzeppelin/contracts/utils/introspection/ERC165.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
@openzeppelin/contracts/utils/introspection/IERC165.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
contracts/MessageLibBase.sol
// SPDX-License-Identifier: LZBL-1.2 pragma solidity ^0.8.20; /// @dev simply a container of endpoint address and local eid abstract contract MessageLibBase { address internal immutable endpoint; uint32 internal immutable localEid; error LZ_MessageLib_OnlyEndpoint(); modifier onlyEndpoint() { if (endpoint != msg.sender) revert LZ_MessageLib_OnlyEndpoint(); _; } constructor(address _endpoint, uint32 _localEid) { endpoint = _endpoint; localEid = _localEid; } }
contracts/ReceiveLibBaseE2.sol
// SPDX-License-Identifier: LZBL-1.2 pragma solidity ^0.8.20; import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import { ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; import { ILayerZeroEndpointV2, Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol"; import { IMessageLib, MessageLibType } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessageLib.sol"; import { PacketV1Codec } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol"; import { MessageLibBase } from "./MessageLibBase.sol"; /// @dev receive-side message library base contract on endpoint v2. /// it does not have the complication as the one of endpoint v1, such as nonce, executor whitelist, etc. abstract contract ReceiveLibBaseE2 is MessageLibBase, ERC165, IMessageLib { using PacketV1Codec for bytes; constructor(address _endpoint) MessageLibBase(_endpoint, ILayerZeroEndpointV2(_endpoint).eid()) {} function supportsInterface(bytes4 _interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { return _interfaceId == type(IMessageLib).interfaceId || super.supportsInterface(_interfaceId); } function messageLibType() external pure virtual override returns (MessageLibType) { return MessageLibType.Receive; } }
contracts/uln/ReceiveUlnBase.sol
// SPDX-License-Identifier: LZBL-1.2 pragma solidity ^0.8.20; import { PacketV1Codec } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol"; import { UlnBase, UlnConfig } from "./UlnBase.sol"; struct Verification { bool submitted; uint64 confirmations; } /// @dev includes the utility functions for checking ULN states and logics abstract contract ReceiveUlnBase is UlnBase { using PacketV1Codec for bytes; mapping(bytes32 headerHash => mapping(bytes32 payloadHash => mapping(address dvn => Verification))) public hashLookup; event PayloadVerified(address dvn, bytes header, uint256 confirmations, bytes32 proofHash); error LZ_ULN_InvalidPacketHeader(); error LZ_ULN_InvalidPacketVersion(); error LZ_ULN_InvalidEid(); error LZ_ULN_Verifying(); // ============================ External =================================== function verifiable( UlnConfig memory _config, bytes32 _headerHash, bytes32 _payloadHash ) external view returns (bool) { return _checkVerifiable(_config, _headerHash, _payloadHash); } function assertHeader(bytes calldata _packetHeader, uint32 _localEid) external pure { _assertHeader(_packetHeader, _localEid); } // ============================ Internal =================================== /// @dev per DVN signing function function _verify(bytes calldata _packetHeader, bytes32 _payloadHash, uint64 _confirmations) internal { hashLookup[keccak256(_packetHeader)][_payloadHash][msg.sender] = Verification(true, _confirmations); emit PayloadVerified(msg.sender, _packetHeader, _confirmations, _payloadHash); } function _verified( address _dvn, bytes32 _headerHash, bytes32 _payloadHash, uint64 _requiredConfirmation ) internal view returns (bool verified) { Verification memory verification = hashLookup[_headerHash][_payloadHash][_dvn]; // return true if the dvn has signed enough confirmations verified = verification.submitted && verification.confirmations >= _requiredConfirmation; } function _verifyAndReclaimStorage(UlnConfig memory _config, bytes32 _headerHash, bytes32 _payloadHash) internal { if (!_checkVerifiable(_config, _headerHash, _payloadHash)) { revert LZ_ULN_Verifying(); } // iterate the required DVNs if (_config.requiredDVNCount > 0) { for (uint8 i = 0; i < _config.requiredDVNCount; ++i) { delete hashLookup[_headerHash][_payloadHash][_config.requiredDVNs[i]]; } } // iterate the optional DVNs if (_config.optionalDVNCount > 0) { for (uint8 i = 0; i < _config.optionalDVNCount; ++i) { delete hashLookup[_headerHash][_payloadHash][_config.optionalDVNs[i]]; } } } function _assertHeader(bytes calldata _packetHeader, uint32 _localEid) internal pure { // assert packet header is of right size 81 if (_packetHeader.length != 81) revert LZ_ULN_InvalidPacketHeader(); // assert packet header version is the same as ULN if (_packetHeader.version() != PacketV1Codec.PACKET_VERSION) revert LZ_ULN_InvalidPacketVersion(); // assert the packet is for this endpoint if (_packetHeader.dstEid() != _localEid) revert LZ_ULN_InvalidEid(); } /// @dev for verifiable view function /// @dev checks if this verification is ready to be committed to the endpoint function _checkVerifiable( UlnConfig memory _config, bytes32 _headerHash, bytes32 _payloadHash ) internal view returns (bool) { // iterate the required DVNs if (_config.requiredDVNCount > 0) { for (uint8 i = 0; i < _config.requiredDVNCount; ++i) { if (!_verified(_config.requiredDVNs[i], _headerHash, _payloadHash, _config.confirmations)) { // return if any of the required DVNs haven't signed return false; } } if (_config.optionalDVNCount == 0) { // returns early if all required DVNs have signed and there are no optional DVNs return true; } } // then it must require optional validations uint8 threshold = _config.optionalDVNThreshold; for (uint8 i = 0; i < _config.optionalDVNCount; ++i) { if (_verified(_config.optionalDVNs[i], _headerHash, _payloadHash, _config.confirmations)) { // increment the optional count if the optional DVN has signed threshold--; if (threshold == 0) { // early return if the optional threshold has hit return true; } } } // return false as a catch-all return false; } }
contracts/uln/UlnBase.sol
// SPDX-License-Identifier: LZBL-1.2 pragma solidity ^0.8.20; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; // the formal properties are documented in the setter functions struct UlnConfig { uint64 confirmations; // we store the length of required DVNs and optional DVNs instead of using DVN.length directly to save gas uint8 requiredDVNCount; // 0 indicate DEFAULT, NIL_DVN_COUNT indicate NONE (to override the value of default) uint8 optionalDVNCount; // 0 indicate DEFAULT, NIL_DVN_COUNT indicate NONE (to override the value of default) uint8 optionalDVNThreshold; // (0, optionalDVNCount] address[] requiredDVNs; // no duplicates. sorted an an ascending order. allowed overlap with optionalDVNs address[] optionalDVNs; // no duplicates. sorted an an ascending order. allowed overlap with requiredDVNs } struct SetDefaultUlnConfigParam { uint32 eid; UlnConfig config; } /// @dev includes the utility functions for checking ULN states and logics abstract contract UlnBase is Ownable { address private constant DEFAULT_CONFIG = address(0); // reserved values for uint8 internal constant DEFAULT = 0; uint8 internal constant NIL_DVN_COUNT = type(uint8).max; uint64 internal constant NIL_CONFIRMATIONS = type(uint64).max; // 127 to prevent total number of DVNs (127 * 2) exceeding uint8.max (255) // by limiting the total size, it would help constraint the design of DVNOptions uint8 private constant MAX_COUNT = (type(uint8).max - 1) / 2; mapping(address oapp => mapping(uint32 eid => UlnConfig)) internal ulnConfigs; error LZ_ULN_Unsorted(); error LZ_ULN_InvalidRequiredDVNCount(); error LZ_ULN_InvalidOptionalDVNCount(); error LZ_ULN_AtLeastOneDVN(); error LZ_ULN_InvalidOptionalDVNThreshold(); error LZ_ULN_InvalidConfirmations(); error LZ_ULN_UnsupportedEid(uint32 eid); event DefaultUlnConfigsSet(SetDefaultUlnConfigParam[] params); event UlnConfigSet(address oapp, uint32 eid, UlnConfig config); // ============================ OnlyOwner =================================== /// @dev about the DEFAULT ULN config /// 1) its values are all LITERAL (e.g. 0 is 0). whereas in the oapp ULN config, 0 (default value) points to the default ULN config /// this design enables the oapp to point to DEFAULT config without explicitly setting the config /// 2) its configuration is more restrictive than the oapp ULN config that /// a) it must not use NIL value, where NIL is used only by oapps to indicate the LITERAL 0 /// b) it must have at least one DVN function setDefaultUlnConfigs(SetDefaultUlnConfigParam[] calldata _params) external onlyOwner { for (uint256 i = 0; i < _params.length; ++i) { SetDefaultUlnConfigParam calldata param = _params[i]; // 2.a must not use NIL if (param.config.requiredDVNCount == NIL_DVN_COUNT) revert LZ_ULN_InvalidRequiredDVNCount(); if (param.config.optionalDVNCount == NIL_DVN_COUNT) revert LZ_ULN_InvalidOptionalDVNCount(); if (param.config.confirmations == NIL_CONFIRMATIONS) revert LZ_ULN_InvalidConfirmations(); // 2.b must have at least one dvn _assertAtLeastOneDVN(param.config); _setConfig(DEFAULT_CONFIG, param.eid, param.config); } emit DefaultUlnConfigsSet(_params); } // ============================ View =================================== // @dev assuming most oapps use default, we get default as memory and custom as storage to save gas function getUlnConfig(address _oapp, uint32 _remoteEid) public view returns (UlnConfig memory rtnConfig) { UlnConfig storage defaultConfig = ulnConfigs[DEFAULT_CONFIG][_remoteEid]; UlnConfig storage customConfig = ulnConfigs[_oapp][_remoteEid]; // if confirmations is 0, use default uint64 confirmations = customConfig.confirmations; if (confirmations == DEFAULT) { rtnConfig.confirmations = defaultConfig.confirmations; } else if (confirmations != NIL_CONFIRMATIONS) { // if confirmations is uint64.max, no block confirmations required rtnConfig.confirmations = confirmations; } // else do nothing, rtnConfig.confirmation is 0 if (customConfig.requiredDVNCount == DEFAULT) { if (defaultConfig.requiredDVNCount > 0) { // copy only if count > 0. save gas rtnConfig.requiredDVNs = defaultConfig.requiredDVNs; rtnConfig.requiredDVNCount = defaultConfig.requiredDVNCount; } // else, do nothing } else { if (customConfig.requiredDVNCount != NIL_DVN_COUNT) { rtnConfig.requiredDVNs = customConfig.requiredDVNs; rtnConfig.requiredDVNCount = customConfig.requiredDVNCount; } // else, do nothing } if (customConfig.optionalDVNCount == DEFAULT) { if (defaultConfig.optionalDVNCount > 0) { // copy only if count > 0. save gas rtnConfig.optionalDVNs = defaultConfig.optionalDVNs; rtnConfig.optionalDVNCount = defaultConfig.optionalDVNCount; rtnConfig.optionalDVNThreshold = defaultConfig.optionalDVNThreshold; } } else { if (customConfig.optionalDVNCount != NIL_DVN_COUNT) { rtnConfig.optionalDVNs = customConfig.optionalDVNs; rtnConfig.optionalDVNCount = customConfig.optionalDVNCount; rtnConfig.optionalDVNThreshold = customConfig.optionalDVNThreshold; } } // the final value must have at least one dvn // it is possible that some default config result into 0 dvns _assertAtLeastOneDVN(rtnConfig); } /// @dev Get the uln config without the default config for the given remoteEid. function getAppUlnConfig(address _oapp, uint32 _remoteEid) external view returns (UlnConfig memory) { return ulnConfigs[_oapp][_remoteEid]; } // ============================ Internal =================================== function _setUlnConfig(uint32 _remoteEid, address _oapp, UlnConfig memory _param) internal { _setConfig(_oapp, _remoteEid, _param); // get ULN config again as a catch all to ensure the config is valid getUlnConfig(_oapp, _remoteEid); emit UlnConfigSet(_oapp, _remoteEid, _param); } /// @dev a supported Eid must have a valid default uln config, which has at least one dvn function _isSupportedEid(uint32 _remoteEid) internal view returns (bool) { UlnConfig storage defaultConfig = ulnConfigs[DEFAULT_CONFIG][_remoteEid]; return defaultConfig.requiredDVNCount > 0 || defaultConfig.optionalDVNThreshold > 0; } function _assertSupportedEid(uint32 _remoteEid) internal view { if (!_isSupportedEid(_remoteEid)) revert LZ_ULN_UnsupportedEid(_remoteEid); } // ============================ Private =================================== function _assertAtLeastOneDVN(UlnConfig memory _config) private pure { if (_config.requiredDVNCount == 0 && _config.optionalDVNThreshold == 0) revert LZ_ULN_AtLeastOneDVN(); } /// @dev this private function is used in both setDefaultUlnConfigs and setUlnConfig function _setConfig(address _oapp, uint32 _eid, UlnConfig memory _param) private { // @dev required dvns // if dvnCount == NONE, dvns list must be empty // if dvnCount == DEFAULT, dvn list must be empty // otherwise, dvnList.length == dvnCount and assert the list is valid if (_param.requiredDVNCount == NIL_DVN_COUNT || _param.requiredDVNCount == DEFAULT) { if (_param.requiredDVNs.length != 0) revert LZ_ULN_InvalidRequiredDVNCount(); } else { if (_param.requiredDVNs.length != _param.requiredDVNCount || _param.requiredDVNCount > MAX_COUNT) revert LZ_ULN_InvalidRequiredDVNCount(); _assertNoDuplicates(_param.requiredDVNs); } // @dev optional dvns // if optionalDVNCount == NONE, optionalDVNs list must be empty and threshold must be 0 // if optionalDVNCount == DEFAULT, optionalDVNs list must be empty and threshold must be 0 // otherwise, optionalDVNs.length == optionalDVNCount, threshold > 0 && threshold <= optionalDVNCount and assert the list is valid // example use case: an oapp uses the DEFAULT 'required' but // a) use a custom 1/1 dvn (practically a required dvn), or // b) use a custom 2/3 dvn if (_param.optionalDVNCount == NIL_DVN_COUNT || _param.optionalDVNCount == DEFAULT) { if (_param.optionalDVNs.length != 0) revert LZ_ULN_InvalidOptionalDVNCount(); if (_param.optionalDVNThreshold != 0) revert LZ_ULN_InvalidOptionalDVNThreshold(); } else { if (_param.optionalDVNs.length != _param.optionalDVNCount || _param.optionalDVNCount > MAX_COUNT) revert LZ_ULN_InvalidOptionalDVNCount(); if (_param.optionalDVNThreshold == 0 || _param.optionalDVNThreshold > _param.optionalDVNCount) revert LZ_ULN_InvalidOptionalDVNThreshold(); _assertNoDuplicates(_param.optionalDVNs); } // don't assert valid count here, as it needs to be validated along side default config ulnConfigs[_oapp][_eid] = _param; } function _assertNoDuplicates(address[] memory _dvns) private pure { address lastDVN = address(0); for (uint256 i = 0; i < _dvns.length; i++) { address dvn = _dvns[i]; if (dvn <= lastDVN) revert LZ_ULN_Unsorted(); // to ensure no duplicates lastDVN = dvn; } } }
contracts/uln/interfaces/IReceiveUlnE2.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.8.0; /// @dev should be implemented by the ReceiveUln302 contract and future ReceiveUln contracts on EndpointV2 interface IReceiveUlnE2 { /// @notice for each dvn to verify the payload /// @dev this function signature 0x0223536e function verify(bytes calldata _packetHeader, bytes32 _payloadHash, uint64 _confirmations) external; /// @notice verify the payload at endpoint, will check if all DVNs verified function commitVerification(bytes calldata _packetHeader, bytes32 _payloadHash) external; }
Compiler Settings
{"outputSelection":{},"optimizer":{"runs":20000,"enabled":true},"libraries":{},"evmVersion":"paris"}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_endpoint","internalType":"address"}]},{"type":"error","name":"LZ_MessageLib_OnlyEndpoint","inputs":[]},{"type":"error","name":"LZ_ULN_AtLeastOneDVN","inputs":[]},{"type":"error","name":"LZ_ULN_InvalidConfigType","inputs":[{"type":"uint32","name":"configType","internalType":"uint32"}]},{"type":"error","name":"LZ_ULN_InvalidConfirmations","inputs":[]},{"type":"error","name":"LZ_ULN_InvalidEid","inputs":[]},{"type":"error","name":"LZ_ULN_InvalidOptionalDVNCount","inputs":[]},{"type":"error","name":"LZ_ULN_InvalidOptionalDVNThreshold","inputs":[]},{"type":"error","name":"LZ_ULN_InvalidPacketHeader","inputs":[]},{"type":"error","name":"LZ_ULN_InvalidPacketVersion","inputs":[]},{"type":"error","name":"LZ_ULN_InvalidRequiredDVNCount","inputs":[]},{"type":"error","name":"LZ_ULN_Unsorted","inputs":[]},{"type":"error","name":"LZ_ULN_UnsupportedEid","inputs":[{"type":"uint32","name":"eid","internalType":"uint32"}]},{"type":"error","name":"LZ_ULN_Verifying","inputs":[]},{"type":"event","name":"DefaultUlnConfigsSet","inputs":[{"type":"tuple[]","name":"params","internalType":"struct SetDefaultUlnConfigParam[]","indexed":false,"components":[{"type":"uint32","name":"eid","internalType":"uint32"},{"type":"tuple","name":"config","internalType":"struct UlnConfig","components":[{"type":"uint64","name":"confirmations","internalType":"uint64"},{"type":"uint8","name":"requiredDVNCount","internalType":"uint8"},{"type":"uint8","name":"optionalDVNCount","internalType":"uint8"},{"type":"uint8","name":"optionalDVNThreshold","internalType":"uint8"},{"type":"address[]","name":"requiredDVNs","internalType":"address[]"},{"type":"address[]","name":"optionalDVNs","internalType":"address[]"}]}]}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"PayloadVerified","inputs":[{"type":"address","name":"dvn","internalType":"address","indexed":false},{"type":"bytes","name":"header","internalType":"bytes","indexed":false},{"type":"uint256","name":"confirmations","internalType":"uint256","indexed":false},{"type":"bytes32","name":"proofHash","internalType":"bytes32","indexed":false}],"anonymous":false},{"type":"event","name":"UlnConfigSet","inputs":[{"type":"address","name":"oapp","internalType":"address","indexed":false},{"type":"uint32","name":"eid","internalType":"uint32","indexed":false},{"type":"tuple","name":"config","internalType":"struct UlnConfig","indexed":false,"components":[{"type":"uint64","name":"confirmations","internalType":"uint64"},{"type":"uint8","name":"requiredDVNCount","internalType":"uint8"},{"type":"uint8","name":"optionalDVNCount","internalType":"uint8"},{"type":"uint8","name":"optionalDVNThreshold","internalType":"uint8"},{"type":"address[]","name":"requiredDVNs","internalType":"address[]"},{"type":"address[]","name":"optionalDVNs","internalType":"address[]"}]}],"anonymous":false},{"type":"function","stateMutability":"pure","outputs":[],"name":"assertHeader","inputs":[{"type":"bytes","name":"_packetHeader","internalType":"bytes"},{"type":"uint32","name":"_localEid","internalType":"uint32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"commitVerification","inputs":[{"type":"bytes","name":"_packetHeader","internalType":"bytes"},{"type":"bytes32","name":"_payloadHash","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct UlnConfig","components":[{"type":"uint64","name":"confirmations","internalType":"uint64"},{"type":"uint8","name":"requiredDVNCount","internalType":"uint8"},{"type":"uint8","name":"optionalDVNCount","internalType":"uint8"},{"type":"uint8","name":"optionalDVNThreshold","internalType":"uint8"},{"type":"address[]","name":"requiredDVNs","internalType":"address[]"},{"type":"address[]","name":"optionalDVNs","internalType":"address[]"}]}],"name":"getAppUlnConfig","inputs":[{"type":"address","name":"_oapp","internalType":"address"},{"type":"uint32","name":"_remoteEid","internalType":"uint32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes","name":"","internalType":"bytes"}],"name":"getConfig","inputs":[{"type":"uint32","name":"_eid","internalType":"uint32"},{"type":"address","name":"_oapp","internalType":"address"},{"type":"uint32","name":"_configType","internalType":"uint32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"rtnConfig","internalType":"struct UlnConfig","components":[{"type":"uint64","name":"confirmations","internalType":"uint64"},{"type":"uint8","name":"requiredDVNCount","internalType":"uint8"},{"type":"uint8","name":"optionalDVNCount","internalType":"uint8"},{"type":"uint8","name":"optionalDVNThreshold","internalType":"uint8"},{"type":"address[]","name":"requiredDVNs","internalType":"address[]"},{"type":"address[]","name":"optionalDVNs","internalType":"address[]"}]}],"name":"getUlnConfig","inputs":[{"type":"address","name":"_oapp","internalType":"address"},{"type":"uint32","name":"_remoteEid","internalType":"uint32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"submitted","internalType":"bool"},{"type":"uint64","name":"confirmations","internalType":"uint64"}],"name":"hashLookup","inputs":[{"type":"bytes32","name":"headerHash","internalType":"bytes32"},{"type":"bytes32","name":"payloadHash","internalType":"bytes32"},{"type":"address","name":"dvn","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isSupportedEid","inputs":[{"type":"uint32","name":"_eid","internalType":"uint32"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint8","name":"","internalType":"enum MessageLibType"}],"name":"messageLibType","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setConfig","inputs":[{"type":"address","name":"_oapp","internalType":"address"},{"type":"tuple[]","name":"_params","internalType":"struct SetConfigParam[]","components":[{"type":"uint32","name":"eid","internalType":"uint32"},{"type":"uint32","name":"configType","internalType":"uint32"},{"type":"bytes","name":"config","internalType":"bytes"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setDefaultUlnConfigs","inputs":[{"type":"tuple[]","name":"_params","internalType":"struct SetDefaultUlnConfigParam[]","components":[{"type":"uint32","name":"eid","internalType":"uint32"},{"type":"tuple","name":"config","internalType":"struct UlnConfig","components":[{"type":"uint64","name":"confirmations","internalType":"uint64"},{"type":"uint8","name":"requiredDVNCount","internalType":"uint8"},{"type":"uint8","name":"optionalDVNCount","internalType":"uint8"},{"type":"uint8","name":"optionalDVNThreshold","internalType":"uint8"},{"type":"address[]","name":"requiredDVNs","internalType":"address[]"},{"type":"address[]","name":"optionalDVNs","internalType":"address[]"}]}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"supportsInterface","inputs":[{"type":"bytes4","name":"_interfaceId","internalType":"bytes4"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"verifiable","inputs":[{"type":"tuple","name":"_config","internalType":"struct UlnConfig","components":[{"type":"uint64","name":"confirmations","internalType":"uint64"},{"type":"uint8","name":"requiredDVNCount","internalType":"uint8"},{"type":"uint8","name":"optionalDVNCount","internalType":"uint8"},{"type":"uint8","name":"optionalDVNThreshold","internalType":"uint8"},{"type":"address[]","name":"requiredDVNs","internalType":"address[]"},{"type":"address[]","name":"optionalDVNs","internalType":"address[]"}]},{"type":"bytes32","name":"_headerHash","internalType":"bytes32"},{"type":"bytes32","name":"_payloadHash","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"verify","inputs":[{"type":"bytes","name":"_packetHeader","internalType":"bytes"},{"type":"bytes32","name":"_payloadHash","internalType":"bytes32"},{"type":"uint64","name":"_confirmations","internalType":"uint64"}]},{"type":"function","stateMutability":"pure","outputs":[{"type":"uint64","name":"major","internalType":"uint64"},{"type":"uint8","name":"minor","internalType":"uint8"},{"type":"uint8","name":"endpointVersion","internalType":"uint8"}],"name":"version","inputs":[]}]
Contract Creation Code
0x60c06040523480156200001157600080fd5b5060405162002c9f38038062002c9f833981016040819052620000349162000116565b8080816001600160a01b031663416ecebf6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000075573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200009b919062000148565b620000a633620000c6565b6001600160a01b0390911660805263ffffffff1660a05250620001709050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000602082840312156200012957600080fd5b81516001600160a01b03811681146200014157600080fd5b9392505050565b6000602082840312156200015b57600080fd5b815163ffffffff811681146200014157600080fd5b60805160a051612b026200019d600039600061036e01526000818161049201526104fb0152612b026000f3fe608060405234801561001057600080fd5b506004361061011b5760003560e01c806343ea4fa9116100b25780638da5cb5b11610081578063c40ff83511610066578063c40ff835146102c0578063e084d952146102d3578063f2fde38b146102e657600080fd5b80638da5cb5b146102785780639c33abf7146102a057600080fd5b806343ea4fa91461022a57806354fd4d501461023d5780636750cd4c1461025d578063715018a61461027057600080fd5b806320efd722116100ee57806320efd7221461017f57806329460b0b1461019257806339e3f938146101a55780633c782a52146101c557600080fd5b806301ffc9a7146101205780630223536e146101485780630894edf11461015d5780631881d94d14610170575b600080fd5b61013361012e366004611cc0565b6102f9565b60405190151581526020015b60405180910390f35b61015b610156366004611d68565b610355565b005b61015b61016b366004611dc5565b610367565b600160405161013f9190611e11565b61015b61018d366004611ebb565b6104f9565b61015b6101a0366004611f0e565b61065a565b6101b86101b3366004611f64565b61083f565b60405161013f919061205b565b61020a6101d336600461206e565b600260209081526000938452604080852082529284528284209052825290205460ff811690610100900467ffffffffffffffff1682565b60408051921515835267ffffffffffffffff90911660208301520161013f565b6101b8610238366004611f64565b6109e0565b60408051600381526000602082015260029181019190915260600161013f565b61013361026b3660046120a3565b610d9a565b61015b610da5565b60005460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161013f565b6102b36102ae3660046120be565b610db9565b60405161013f91906120f8565b61015b6102ce366004612165565b610e59565b6101336102e136600461238f565b610e69565b61015b6102f43660046123dd565b610e7e565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f0ab7be9f00000000000000000000000000000000000000000000000000000000148061034f575061034f82610f35565b92915050565b61036184848484610fcc565b50505050565b61039283837f00000000000000000000000000000000000000000000000000000000000000006110e0565b600061039e84846111ae565b905060006103ac85856111c0565b905060006103ba83836109e0565b90506103de8187876040516103d09291906123f8565b6040518091039020866111e3565b600060405180606001604052808463ffffffff1681526020016104018989611392565b815260200161041089896113ab565b67ffffffffffffffff908116909152604080517fa825d747000000000000000000000000000000000000000000000000000000008152835163ffffffff1660048201526020840151602482015290830151909116604482015273ffffffffffffffffffffffffffffffffffffffff8681166064830152608482018890529192507f00000000000000000000000000000000000000000000000000000000000000009091169063a825d7479060a401600060405180830381600087803b1580156104d857600080fd5b505af11580156104ec573d6000803e3d6000fd5b5050505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163314610568576040517f467409c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610361573683838381811061058657610586612408565b90506020028101906105989190612437565b90506105af6105aa60208301836120a3565b6113ce565b60026105c160408301602084016120a3565b63ffffffff1603610601576105fc6105dc60208301836120a3565b866105ea6040850185612475565b8101906105f791906124da565b611415565b610651565b61061160408201602083016120a3565b6040517fba97c1fa00000000000000000000000000000000000000000000000000000000815263ffffffff90911660048201526024015b60405180910390fd5b5060010161056b565b61066261146b565b60005b81811015610801573683838381811061068057610680612408565b9050602002810190610692919061250f565b905060ff6106a36020830183612543565b6106b4906040810190602001612577565b60ff16036106ee576040517f83aa17da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ff6106fd6020830183612543565b61070e906060810190604001612577565b60ff1603610748576040517f4221136600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff61075e6020830183612543565b61076c906020810190612592565b67ffffffffffffffff16036107ad576040517f503667ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107cb6107bd6020830183612543565b6107c6906125ad565b6114ec565b6107f860006107dd60208401846120a3565b6107ea6020850185612543565b6107f3906125ad565b61153d565b50600101610665565b507faaf3aaa0c11056e86ac56eb653e25b005ca1a7d4dcd21ba24647f7ab63f3b5608282604051610833929190612669565b60405180910390a15050565b6040805160c0810182526000808252602082018190529181018290526060808201929092526080810182905260a081019190915273ffffffffffffffffffffffffffffffffffffffff8316600090815260016020818152604080842063ffffffff87168552825292839020835160c081018552815467ffffffffffffffff8116825260ff680100000000000000008204811683860152690100000000000000000082048116838801526a0100000000000000000000909104166060820152928101805485518185028101850190965280865293949193608086019383018282801561096057602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610935575b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156109cf57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116109a4575b505050505081525050905092915050565b6040805160c0810182526000808252602080830182905282840182905260608084018390526080840181905260a084015263ffffffff85168083527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb49825284832073ffffffffffffffffffffffffffffffffffffffff88168452600183528584209184529152929020805491929167ffffffffffffffff1680610a9057825467ffffffffffffffff168452610aaf565b67ffffffffffffffff81811614610aaf5767ffffffffffffffff811684525b815468010000000000000000900460ff16610b6557825468010000000000000000900460ff1615610b605782600101805480602002602001604051908101604052809291908181526020018280548015610b3f57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610b14575b50505050506080850152825468010000000000000000900460ff1660208501525b610c03565b815468010000000000000000900460ff90811614610c035781600101805480602002602001604051908101604052809291908181526020018280548015610be257602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610bb7575b50505050506080850152815468010000000000000000900460ff1660208501525b81546901000000000000000000900460ff16610cd25782546901000000000000000000900460ff1615610ccd5782600201805480602002602001604051908101604052809291908181526020018280548015610c9557602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610c6a575b505050505060a0850152825460ff69010000000000000000008204811660408701526a01000000000000000000009091041660608501525b610d88565b81546901000000000000000000900460ff90811614610d885781600201805480602002602001604051908101604052809291908181526020018280548015610d5057602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610d25575b505050505060a0850152815460ff69010000000000000000008204811660408701526a01000000000000000000009091041660608501525b610d91846114ec565b50505092915050565b600061034f826118d1565b610dad61146b565b610db76000611938565b565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe63ffffffff831601610e1857610df283856109e0565b604051602001610e02919061205b565b6040516020818303038152906040529050610e52565b6040517fba97c1fa00000000000000000000000000000000000000000000000000000000815263ffffffff83166004820152602401610648565b9392505050565b610e648383836110e0565b505050565b6000610e768484846119ad565b949350505050565b610e8661146b565b73ffffffffffffffffffffffffffffffffffffffff8116610f29576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610648565b610f3281611938565b50565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f97f0258400000000000000000000000000000000000000000000000000000000148061034f57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161461034f565b6040805180820182526001815267ffffffffffffffff831660208201529051600290600090610ffe90889088906123f8565b6040805191829003909120825260208083019390935290810160009081208682528352818120338083529084529082902084518154959094015167ffffffffffffffff16610100027fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ff941515949094167fffffffffffffffffffffffffffffffffffffffffffffff000000000000000000909516949094179290921790925590517f2cb0eed7538baeae4c6fde038c0fd0384d27de0dd55a228c65847bda6aa1ab56916110d2918790879086908890612806565b60405180910390a150505050565b6051821461111a576040517fc9bf37b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016111268484611ab6565b60ff1614611160576040517f3a9ae7b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8063ffffffff166111718484611ad8565b63ffffffff1614610e64576040517f42d2c97e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610e526111bd8484611ae8565b90565b60006111d0600d6009848661288b565b6111d9916128b5565b60e01c9392505050565b6111ee8383836119ad565b611224576040517f4c3118d400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602083015160ff16156112dc5760005b836020015160ff168160ff1610156112da57600083815260026020908152604080832085845290915281206080860151805191929160ff851690811061127c5761127c612408565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffff000000000000000000169055600101611234565b505b604083015160ff1615610e645760005b836040015160ff168160ff161015610361576000838152600260209081526040808320858452909152812060a0860151805191929160ff851690811061133457611334612408565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000001690556001016112ec565b60006113a2602d600d848661288b565b610e52916128fd565b60006113bb60096001848661288b565b6113c491612939565b60c01c9392505050565b6113d7816118d1565b610f32576040517ff0c10d0400000000000000000000000000000000000000000000000000000000815263ffffffff82166004820152602401610648565b61142082848361153d565b61142a82846109e0565b507f82118522aa536ac0e96cc5c689407ae42b89d592aa133890a01f1509842f508182848360405161145e9392919061297f565b60405180910390a1505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610db7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610648565b602081015160ff161580156115065750606081015160ff16155b15610f32576040517fce2c375100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602081015160ff90811614806115585750602081015160ff16155b1561159f576080810151511561159a576040517f83aa17da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61161e565b806020015160ff168160800151511415806115da575060026115c3600160ff6129e9565b6115cd9190612a02565b60ff16816020015160ff16115b15611611576040517f83aa17da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61161e8160800151611af8565b604081015160ff90811614806116395750604081015160ff16155b156116bf5760a0810151511561167b576040517f4221136600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606081015160ff16156116ba576040517f38682fa900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611796565b806040015160ff168160a00151511415806116fa575060026116e3600160ff6129e9565b6116ed9190612a02565b60ff16816040015160ff16115b15611731576040517f4221136600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606081015160ff1615806117525750806040015160ff16816060015160ff16115b15611789576040517f38682fa900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6117968160a00151611af8565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260016020818152604080842063ffffffff87168552825292839020845181548684015195870151606088015167ffffffffffffffff9093167fffffffffffffffffffffffffffffffffffffffffffffff000000000000000000909216919091176801000000000000000060ff97881602177fffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffff166901000000000000000000918716919091027fffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffff16176a01000000000000000000009590911694909402939093178355608084015180518594936118ad93908501920190611c21565b5060a082015180516118c9916002840191602090910190611c21565b505050505050565b63ffffffff811660009081527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb4960205260408120805468010000000000000000900460ff16151580610e525750546a0100000000000000000000900460ff16151592915050565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b602083015160009060ff1615611a305760005b846020015160ff168160ff161015611a1857611a0285608001518260ff16815181106119ee576119ee612408565b602002602001015185858860000151611b92565b611a10576000915050610e52565b6001016119c0565b50836040015160ff16600003611a3057506001610e52565b606084015160005b856040015160ff168160ff161015611aaa57611a7a8660a001518260ff1681518110611a6657611a66612408565b602002602001015186868960000151611b92565b15611aa25781611a8981612a4b565b9250508160ff16600003611aa257600192505050610e52565b600101611a38565b50600095945050505050565b6000611ac5600182848661288b565b611ace91612a86565b60f81c9392505050565b60006111d06031602d848661288b565b60006113a260516031848661288b565b6000805b8251811015610e64576000838281518110611b1957611b19612408565b602002602001015190508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1611611b88576040517f447516e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9150600101611afc565b6000838152600260209081526040808320858452825280832073ffffffffffffffffffffffffffffffffffffffff88168452825280832081518083019092525460ff811615801580845261010090920467ffffffffffffffff16938301939093529091611c1757508267ffffffffffffffff16816020015167ffffffffffffffff1610155b9695505050505050565b828054828255906000526020600020908101928215611c9b579160200282015b82811115611c9b57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190611c41565b50611ca7929150611cab565b5090565b5b80821115611ca75760008155600101611cac565b600060208284031215611cd257600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610e5257600080fd5b60008083601f840112611d1457600080fd5b50813567ffffffffffffffff811115611d2c57600080fd5b602083019150836020828501011115611d4457600080fd5b9250929050565b803567ffffffffffffffff81168114611d6357600080fd5b919050565b60008060008060608587031215611d7e57600080fd5b843567ffffffffffffffff811115611d9557600080fd5b611da187828801611d02565b90955093505060208501359150611dba60408601611d4b565b905092959194509250565b600080600060408486031215611dda57600080fd5b833567ffffffffffffffff811115611df157600080fd5b611dfd86828701611d02565b909790965060209590950135949350505050565b6020810160038310611e4c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b803573ffffffffffffffffffffffffffffffffffffffff81168114611d6357600080fd5b60008083601f840112611e8857600080fd5b50813567ffffffffffffffff811115611ea057600080fd5b6020830191508360208260051b8501011115611d4457600080fd5b600080600060408486031215611ed057600080fd5b611ed984611e52565b9250602084013567ffffffffffffffff811115611ef557600080fd5b611f0186828701611e76565b9497909650939450505050565b60008060208385031215611f2157600080fd5b823567ffffffffffffffff811115611f3857600080fd5b611f4485828601611e76565b90969095509350505050565b803563ffffffff81168114611d6357600080fd5b60008060408385031215611f7757600080fd5b611f8083611e52565b9150611f8e60208401611f50565b90509250929050565b60008151808452602080850194506020840160005b83811015611fde57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101611fac565b509495945050505050565b67ffffffffffffffff815116825260ff602082015116602083015260ff604082015116604083015260ff60608201511660608301526000608082015160c0608085015261203960c0850182611f97565b905060a083015184820360a08601526120528282611f97565b95945050505050565b602081526000610e526020830184611fe9565b60008060006060848603121561208357600080fd5b833592506020840135915061209a60408501611e52565b90509250925092565b6000602082840312156120b557600080fd5b610e5282611f50565b6000806000606084860312156120d357600080fd5b6120dc84611f50565b92506120ea60208501611e52565b915061209a60408501611f50565b60006020808352835180602085015260005b818110156121265785810183015185820160400152820161210a565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b60008060006040848603121561217a57600080fd5b833567ffffffffffffffff81111561219157600080fd5b61219d86828701611d02565b909450925061209a905060208501611f50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715612202576122026121b0565b60405290565b803560ff81168114611d6357600080fd5b600082601f83011261222a57600080fd5b8135602067ffffffffffffffff80831115612247576122476121b0565b8260051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110848211171561228a5761228a6121b0565b60405293845260208187018101949081019250878511156122aa57600080fd5b6020870191505b848210156122d1576122c282611e52565b835291830191908301906122b1565b979650505050505050565b600060c082840312156122ee57600080fd5b6122f66121df565b905061230182611d4b565b815261230f60208301612208565b602082015261232060408301612208565b604082015261233160608301612208565b6060820152608082013567ffffffffffffffff8082111561235157600080fd5b61235d85838601612219565b608084015260a084013591508082111561237657600080fd5b5061238384828501612219565b60a08301525092915050565b6000806000606084860312156123a457600080fd5b833567ffffffffffffffff8111156123bb57600080fd5b6123c7868287016122dc565b9660208601359650604090950135949350505050565b6000602082840312156123ef57600080fd5b610e5282611e52565b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa183360301811261246b57600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126124aa57600080fd5b83018035915067ffffffffffffffff8211156124c557600080fd5b602001915036819003821315611d4457600080fd5b6000602082840312156124ec57600080fd5b813567ffffffffffffffff81111561250357600080fd5b610e76848285016122dc565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261246b57600080fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4183360301811261246b57600080fd5b60006020828403121561258957600080fd5b610e5282612208565b6000602082840312156125a457600080fd5b610e5282611d4b565b600061034f36836122dc565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126125ee57600080fd5b830160208101925035905067ffffffffffffffff81111561260e57600080fd5b8060051b3603821315611d4457600080fd5b8183526000602080850194508260005b85811015611fde5773ffffffffffffffffffffffffffffffffffffffff61265683611e52565b1687529582019590820190600101612630565b60208082528181018390526000906040808401600586901b8501820187855b888110156127f8577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08089850301855282357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18c36030181126126ea57600080fd5b8b0163ffffffff6126fa82611f50565b168552878101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4182360301811261273157600080fd5b8589018890520167ffffffffffffffff61274a82611d4b565b168786015261275a888201612208565b606060ff808316828901526127708a8501612208565b92506080818416818a0152612786838601612208565b935060a09250818416838a015261279f818601866125b9565b60c08b810152945091506127ba905061010089018483612620565b9250506127c9818401846125b9565b93509050838783030160e08801526127e2828483612620565b978a019796505050928701925050600101612688565b509098975050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8616815260806020820152836080820152838560a0830137600060a08583010152600060a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f870116830101905067ffffffffffffffff841660408301528260608301529695505050505050565b6000808585111561289b57600080fd5b838611156128a857600080fd5b5050820193919092039150565b7fffffffff0000000000000000000000000000000000000000000000000000000081358181169160048510156128f55780818660040360031b1b83161692505b505092915050565b8035602083101561034f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b7fffffffffffffffff00000000000000000000000000000000000000000000000081358181169160088510156128f55760089490940360031b84901b1690921692915050565b73ffffffffffffffffffffffffffffffffffffffff8416815263ffffffff831660208201526060604082015260006120526060830184611fe9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60ff828116828216039081111561034f5761034f6129ba565b600060ff831680612a3c577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8060ff84160491505092915050565b600060ff821680612a5e57612a5e6129ba565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192915050565b7fff0000000000000000000000000000000000000000000000000000000000000081358181169160018510156128f55760019490940360031b84901b169092169291505056fea2646970667358221220ace23e3b0bf7b28db46f2e1ed63ac9c07024c1c7084798c13b15e41cc054e39564736f6c634300081600330000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b
Deployed ByteCode
0x608060405234801561001057600080fd5b506004361061011b5760003560e01c806343ea4fa9116100b25780638da5cb5b11610081578063c40ff83511610066578063c40ff835146102c0578063e084d952146102d3578063f2fde38b146102e657600080fd5b80638da5cb5b146102785780639c33abf7146102a057600080fd5b806343ea4fa91461022a57806354fd4d501461023d5780636750cd4c1461025d578063715018a61461027057600080fd5b806320efd722116100ee57806320efd7221461017f57806329460b0b1461019257806339e3f938146101a55780633c782a52146101c557600080fd5b806301ffc9a7146101205780630223536e146101485780630894edf11461015d5780631881d94d14610170575b600080fd5b61013361012e366004611cc0565b6102f9565b60405190151581526020015b60405180910390f35b61015b610156366004611d68565b610355565b005b61015b61016b366004611dc5565b610367565b600160405161013f9190611e11565b61015b61018d366004611ebb565b6104f9565b61015b6101a0366004611f0e565b61065a565b6101b86101b3366004611f64565b61083f565b60405161013f919061205b565b61020a6101d336600461206e565b600260209081526000938452604080852082529284528284209052825290205460ff811690610100900467ffffffffffffffff1682565b60408051921515835267ffffffffffffffff90911660208301520161013f565b6101b8610238366004611f64565b6109e0565b60408051600381526000602082015260029181019190915260600161013f565b61013361026b3660046120a3565b610d9a565b61015b610da5565b60005460405173ffffffffffffffffffffffffffffffffffffffff909116815260200161013f565b6102b36102ae3660046120be565b610db9565b60405161013f91906120f8565b61015b6102ce366004612165565b610e59565b6101336102e136600461238f565b610e69565b61015b6102f43660046123dd565b610e7e565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f0ab7be9f00000000000000000000000000000000000000000000000000000000148061034f575061034f82610f35565b92915050565b61036184848484610fcc565b50505050565b61039283837f000000000000000000000000000000000000000000000000000000000000766b6110e0565b600061039e84846111ae565b905060006103ac85856111c0565b905060006103ba83836109e0565b90506103de8187876040516103d09291906123f8565b6040518091039020866111e3565b600060405180606001604052808463ffffffff1681526020016104018989611392565b815260200161041089896113ab565b67ffffffffffffffff908116909152604080517fa825d747000000000000000000000000000000000000000000000000000000008152835163ffffffff1660048201526020840151602482015290830151909116604482015273ffffffffffffffffffffffffffffffffffffffff8681166064830152608482018890529192507f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b9091169063a825d7479060a401600060405180830381600087803b1580156104d857600080fd5b505af11580156104ec573d6000803e3d6000fd5b5050505050505050505050565b7f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b73ffffffffffffffffffffffffffffffffffffffff163314610568576040517f467409c300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610361573683838381811061058657610586612408565b90506020028101906105989190612437565b90506105af6105aa60208301836120a3565b6113ce565b60026105c160408301602084016120a3565b63ffffffff1603610601576105fc6105dc60208301836120a3565b866105ea6040850185612475565b8101906105f791906124da565b611415565b610651565b61061160408201602083016120a3565b6040517fba97c1fa00000000000000000000000000000000000000000000000000000000815263ffffffff90911660048201526024015b60405180910390fd5b5060010161056b565b61066261146b565b60005b81811015610801573683838381811061068057610680612408565b9050602002810190610692919061250f565b905060ff6106a36020830183612543565b6106b4906040810190602001612577565b60ff16036106ee576040517f83aa17da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ff6106fd6020830183612543565b61070e906060810190604001612577565b60ff1603610748576040517f4221136600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff61075e6020830183612543565b61076c906020810190612592565b67ffffffffffffffff16036107ad576040517f503667ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107cb6107bd6020830183612543565b6107c6906125ad565b6114ec565b6107f860006107dd60208401846120a3565b6107ea6020850185612543565b6107f3906125ad565b61153d565b50600101610665565b507faaf3aaa0c11056e86ac56eb653e25b005ca1a7d4dcd21ba24647f7ab63f3b5608282604051610833929190612669565b60405180910390a15050565b6040805160c0810182526000808252602082018190529181018290526060808201929092526080810182905260a081019190915273ffffffffffffffffffffffffffffffffffffffff8316600090815260016020818152604080842063ffffffff87168552825292839020835160c081018552815467ffffffffffffffff8116825260ff680100000000000000008204811683860152690100000000000000000082048116838801526a0100000000000000000000909104166060820152928101805485518185028101850190965280865293949193608086019383018282801561096057602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610935575b50505050508152602001600282018054806020026020016040519081016040528092919081815260200182805480156109cf57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff1681526001909101906020018083116109a4575b505050505081525050905092915050565b6040805160c0810182526000808252602080830182905282840182905260608084018390526080840181905260a084015263ffffffff85168083527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb49825284832073ffffffffffffffffffffffffffffffffffffffff88168452600183528584209184529152929020805491929167ffffffffffffffff1680610a9057825467ffffffffffffffff168452610aaf565b67ffffffffffffffff81811614610aaf5767ffffffffffffffff811684525b815468010000000000000000900460ff16610b6557825468010000000000000000900460ff1615610b605782600101805480602002602001604051908101604052809291908181526020018280548015610b3f57602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610b14575b50505050506080850152825468010000000000000000900460ff1660208501525b610c03565b815468010000000000000000900460ff90811614610c035781600101805480602002602001604051908101604052809291908181526020018280548015610be257602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610bb7575b50505050506080850152815468010000000000000000900460ff1660208501525b81546901000000000000000000900460ff16610cd25782546901000000000000000000900460ff1615610ccd5782600201805480602002602001604051908101604052809291908181526020018280548015610c9557602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610c6a575b505050505060a0850152825460ff69010000000000000000008204811660408701526a01000000000000000000009091041660608501525b610d88565b81546901000000000000000000900460ff90811614610d885781600201805480602002602001604051908101604052809291908181526020018280548015610d5057602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610d25575b505050505060a0850152815460ff69010000000000000000008204811660408701526a01000000000000000000009091041660608501525b610d91846114ec565b50505092915050565b600061034f826118d1565b610dad61146b565b610db76000611938565b565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe63ffffffff831601610e1857610df283856109e0565b604051602001610e02919061205b565b6040516020818303038152906040529050610e52565b6040517fba97c1fa00000000000000000000000000000000000000000000000000000000815263ffffffff83166004820152602401610648565b9392505050565b610e648383836110e0565b505050565b6000610e768484846119ad565b949350505050565b610e8661146b565b73ffffffffffffffffffffffffffffffffffffffff8116610f29576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610648565b610f3281611938565b50565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f97f0258400000000000000000000000000000000000000000000000000000000148061034f57507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161461034f565b6040805180820182526001815267ffffffffffffffff831660208201529051600290600090610ffe90889088906123f8565b6040805191829003909120825260208083019390935290810160009081208682528352818120338083529084529082902084518154959094015167ffffffffffffffff16610100027fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ff941515949094167fffffffffffffffffffffffffffffffffffffffffffffff000000000000000000909516949094179290921790925590517f2cb0eed7538baeae4c6fde038c0fd0384d27de0dd55a228c65847bda6aa1ab56916110d2918790879086908890612806565b60405180910390a150505050565b6051821461111a576040517fc9bf37b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016111268484611ab6565b60ff1614611160576040517f3a9ae7b900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8063ffffffff166111718484611ad8565b63ffffffff1614610e64576040517f42d2c97e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610e526111bd8484611ae8565b90565b60006111d0600d6009848661288b565b6111d9916128b5565b60e01c9392505050565b6111ee8383836119ad565b611224576040517f4c3118d400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602083015160ff16156112dc5760005b836020015160ff168160ff1610156112da57600083815260026020908152604080832085845290915281206080860151805191929160ff851690811061127c5761127c612408565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffff000000000000000000169055600101611234565b505b604083015160ff1615610e645760005b836040015160ff168160ff161015610361576000838152600260209081526040808320858452909152812060a0860151805191929160ff851690811061133457611334612408565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffff0000000000000000001690556001016112ec565b60006113a2602d600d848661288b565b610e52916128fd565b60006113bb60096001848661288b565b6113c491612939565b60c01c9392505050565b6113d7816118d1565b610f32576040517ff0c10d0400000000000000000000000000000000000000000000000000000000815263ffffffff82166004820152602401610648565b61142082848361153d565b61142a82846109e0565b507f82118522aa536ac0e96cc5c689407ae42b89d592aa133890a01f1509842f508182848360405161145e9392919061297f565b60405180910390a1505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610db7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610648565b602081015160ff161580156115065750606081015160ff16155b15610f32576040517fce2c375100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602081015160ff90811614806115585750602081015160ff16155b1561159f576080810151511561159a576040517f83aa17da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61161e565b806020015160ff168160800151511415806115da575060026115c3600160ff6129e9565b6115cd9190612a02565b60ff16816020015160ff16115b15611611576040517f83aa17da00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61161e8160800151611af8565b604081015160ff90811614806116395750604081015160ff16155b156116bf5760a0810151511561167b576040517f4221136600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606081015160ff16156116ba576040517f38682fa900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611796565b806040015160ff168160a00151511415806116fa575060026116e3600160ff6129e9565b6116ed9190612a02565b60ff16816040015160ff16115b15611731576040517f4221136600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606081015160ff1615806117525750806040015160ff16816060015160ff16115b15611789576040517f38682fa900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6117968160a00151611af8565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260016020818152604080842063ffffffff87168552825292839020845181548684015195870151606088015167ffffffffffffffff9093167fffffffffffffffffffffffffffffffffffffffffffffff000000000000000000909216919091176801000000000000000060ff97881602177fffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffff166901000000000000000000918716919091027fffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffff16176a01000000000000000000009590911694909402939093178355608084015180518594936118ad93908501920190611c21565b5060a082015180516118c9916002840191602090910190611c21565b505050505050565b63ffffffff811660009081527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb4960205260408120805468010000000000000000900460ff16151580610e525750546a0100000000000000000000900460ff16151592915050565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b602083015160009060ff1615611a305760005b846020015160ff168160ff161015611a1857611a0285608001518260ff16815181106119ee576119ee612408565b602002602001015185858860000151611b92565b611a10576000915050610e52565b6001016119c0565b50836040015160ff16600003611a3057506001610e52565b606084015160005b856040015160ff168160ff161015611aaa57611a7a8660a001518260ff1681518110611a6657611a66612408565b602002602001015186868960000151611b92565b15611aa25781611a8981612a4b565b9250508160ff16600003611aa257600192505050610e52565b600101611a38565b50600095945050505050565b6000611ac5600182848661288b565b611ace91612a86565b60f81c9392505050565b60006111d06031602d848661288b565b60006113a260516031848661288b565b6000805b8251811015610e64576000838281518110611b1957611b19612408565b602002602001015190508273ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1611611b88576040517f447516e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9150600101611afc565b6000838152600260209081526040808320858452825280832073ffffffffffffffffffffffffffffffffffffffff88168452825280832081518083019092525460ff811615801580845261010090920467ffffffffffffffff16938301939093529091611c1757508267ffffffffffffffff16816020015167ffffffffffffffff1610155b9695505050505050565b828054828255906000526020600020908101928215611c9b579160200282015b82811115611c9b57825182547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909116178255602090920191600190910190611c41565b50611ca7929150611cab565b5090565b5b80821115611ca75760008155600101611cac565b600060208284031215611cd257600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610e5257600080fd5b60008083601f840112611d1457600080fd5b50813567ffffffffffffffff811115611d2c57600080fd5b602083019150836020828501011115611d4457600080fd5b9250929050565b803567ffffffffffffffff81168114611d6357600080fd5b919050565b60008060008060608587031215611d7e57600080fd5b843567ffffffffffffffff811115611d9557600080fd5b611da187828801611d02565b90955093505060208501359150611dba60408601611d4b565b905092959194509250565b600080600060408486031215611dda57600080fd5b833567ffffffffffffffff811115611df157600080fd5b611dfd86828701611d02565b909790965060209590950135949350505050565b6020810160038310611e4c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b803573ffffffffffffffffffffffffffffffffffffffff81168114611d6357600080fd5b60008083601f840112611e8857600080fd5b50813567ffffffffffffffff811115611ea057600080fd5b6020830191508360208260051b8501011115611d4457600080fd5b600080600060408486031215611ed057600080fd5b611ed984611e52565b9250602084013567ffffffffffffffff811115611ef557600080fd5b611f0186828701611e76565b9497909650939450505050565b60008060208385031215611f2157600080fd5b823567ffffffffffffffff811115611f3857600080fd5b611f4485828601611e76565b90969095509350505050565b803563ffffffff81168114611d6357600080fd5b60008060408385031215611f7757600080fd5b611f8083611e52565b9150611f8e60208401611f50565b90509250929050565b60008151808452602080850194506020840160005b83811015611fde57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101611fac565b509495945050505050565b67ffffffffffffffff815116825260ff602082015116602083015260ff604082015116604083015260ff60608201511660608301526000608082015160c0608085015261203960c0850182611f97565b905060a083015184820360a08601526120528282611f97565b95945050505050565b602081526000610e526020830184611fe9565b60008060006060848603121561208357600080fd5b833592506020840135915061209a60408501611e52565b90509250925092565b6000602082840312156120b557600080fd5b610e5282611f50565b6000806000606084860312156120d357600080fd5b6120dc84611f50565b92506120ea60208501611e52565b915061209a60408501611f50565b60006020808352835180602085015260005b818110156121265785810183015185820160400152820161210a565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b60008060006040848603121561217a57600080fd5b833567ffffffffffffffff81111561219157600080fd5b61219d86828701611d02565b909450925061209a905060208501611f50565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160c0810167ffffffffffffffff81118282101715612202576122026121b0565b60405290565b803560ff81168114611d6357600080fd5b600082601f83011261222a57600080fd5b8135602067ffffffffffffffff80831115612247576122476121b0565b8260051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f8301168101818110848211171561228a5761228a6121b0565b60405293845260208187018101949081019250878511156122aa57600080fd5b6020870191505b848210156122d1576122c282611e52565b835291830191908301906122b1565b979650505050505050565b600060c082840312156122ee57600080fd5b6122f66121df565b905061230182611d4b565b815261230f60208301612208565b602082015261232060408301612208565b604082015261233160608301612208565b6060820152608082013567ffffffffffffffff8082111561235157600080fd5b61235d85838601612219565b608084015260a084013591508082111561237657600080fd5b5061238384828501612219565b60a08301525092915050565b6000806000606084860312156123a457600080fd5b833567ffffffffffffffff8111156123bb57600080fd5b6123c7868287016122dc565b9660208601359650604090950135949350505050565b6000602082840312156123ef57600080fd5b610e5282611e52565b8183823760009101908152919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa183360301811261246b57600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126124aa57600080fd5b83018035915067ffffffffffffffff8211156124c557600080fd5b602001915036819003821315611d4457600080fd5b6000602082840312156124ec57600080fd5b813567ffffffffffffffff81111561250357600080fd5b610e76848285016122dc565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc183360301811261246b57600080fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4183360301811261246b57600080fd5b60006020828403121561258957600080fd5b610e5282612208565b6000602082840312156125a457600080fd5b610e5282611d4b565b600061034f36836122dc565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126125ee57600080fd5b830160208101925035905067ffffffffffffffff81111561260e57600080fd5b8060051b3603821315611d4457600080fd5b8183526000602080850194508260005b85811015611fde5773ffffffffffffffffffffffffffffffffffffffff61265683611e52565b1687529582019590820190600101612630565b60208082528181018390526000906040808401600586901b8501820187855b888110156127f8577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08089850301855282357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc18c36030181126126ea57600080fd5b8b0163ffffffff6126fa82611f50565b168552878101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4182360301811261273157600080fd5b8589018890520167ffffffffffffffff61274a82611d4b565b168786015261275a888201612208565b606060ff808316828901526127708a8501612208565b92506080818416818a0152612786838601612208565b935060a09250818416838a015261279f818601866125b9565b60c08b810152945091506127ba905061010089018483612620565b9250506127c9818401846125b9565b93509050838783030160e08801526127e2828483612620565b978a019796505050928701925050600101612688565b509098975050505050505050565b73ffffffffffffffffffffffffffffffffffffffff8616815260806020820152836080820152838560a0830137600060a08583010152600060a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f870116830101905067ffffffffffffffff841660408301528260608301529695505050505050565b6000808585111561289b57600080fd5b838611156128a857600080fd5b5050820193919092039150565b7fffffffff0000000000000000000000000000000000000000000000000000000081358181169160048510156128f55780818660040360031b1b83161692505b505092915050565b8035602083101561034f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b7fffffffffffffffff00000000000000000000000000000000000000000000000081358181169160088510156128f55760089490940360031b84901b1690921692915050565b73ffffffffffffffffffffffffffffffffffffffff8416815263ffffffff831660208201526060604082015260006120526060830184611fe9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60ff828116828216039081111561034f5761034f6129ba565b600060ff831680612a3c577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8060ff84160491505092915050565b600060ff821680612a5e57612a5e6129ba565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0192915050565b7fff0000000000000000000000000000000000000000000000000000000000000081358181169160018510156128f55760019490940360031b84901b169092169291505056fea2646970667358221220ace23e3b0bf7b28db46f2e1ed63ac9c07024c1c7084798c13b15e41cc054e39564736f6c63430008160033