Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 11237642 | 317 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
OUpgradeable
Compiler Version
v0.8.22+commit.4fc1097e
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.22;
import { OFTCoreUpgradeable } from "@layerzerolabs/oft-evm-upgradeable/contracts/oft/OFTCoreUpgradeable.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { IERC7802 } from "./interfaces/IERC7802.sol";
interface IOFTToken is IERC20Metadata, IERC7802 {
}
contract OUpgradeable is OFTCoreUpgradeable {
IOFTToken internal immutable token_;
function token() external view returns (address) {
return address(token_);
}
constructor(
address _lzEndpoint,
IOFTToken _token
) OFTCoreUpgradeable(_token.decimals(), _lzEndpoint) {
token_ = _token;
_disableInitializers();
}
function initialize(address _delegate) public initializer {
__OFTCore_init(_delegate);
__Ownable_init(_delegate);
}
/**
* @notice Indicates whether the OFT contract requires approval of the 'token()' to send.
* @return requiresApproval Needs approval of the underlying token implementation.
*
* @dev In the case of OFT where the contract IS the token, approval is NOT required.
*/
function approvalRequired() external pure virtual returns (bool) {
return false;
}
/**
* @dev Burns tokens from the sender's specified balance.
* @param _from The address to debit the tokens from.
* @param _amountLD The amount of tokens to send in local decimals.
* @param _minAmountLD The minimum amount to send in local decimals.
* @param _dstEid The destination chain ID.
* @return amountSentLD The amount sent in local decimals.
* @return amountReceivedLD The amount received in local decimals on the remote.
*/
function _debit(
address _from,
uint256 _amountLD,
uint256 _minAmountLD,
uint32 _dstEid
) internal virtual override returns (uint256 amountSentLD, uint256 amountReceivedLD) {
(amountSentLD, amountReceivedLD) = _debitView(_amountLD, _minAmountLD, _dstEid);
// @dev In NON-default OFT, amountSentLD could be 100, with a 10% fee, the amountReceivedLD amount is 90,
// therefore amountSentLD CAN differ from amountReceivedLD.
// @dev Default OFT burns on src.
token_.crosschainBurn(_from, amountSentLD);
}
/**
* @dev Credits tokens to the specified address.
* @param _to The address to credit the tokens to.
* @param _amountLD The amount of tokens to credit in local decimals.
* @dev _srcEid The source chain ID.
* @return amountReceivedLD The amount of tokens ACTUALLY received in local decimals.
*/
function _credit(
address _to,
uint256 _amountLD,
uint32 /*_srcEid*/
) internal virtual override returns (uint256 amountReceivedLD) {
if (_to == address(0x0)) _to = address(0xdead); // _mint(...) does not support address(0x0)
// @dev Default OFT mints on dst.
token_.crosschainMint(_to, _amountLD);
// @dev In the case of NON-default OFT, the _amountLD MIGHT not be == amountReceivedLD.
return _amountLD;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/**
* @title ILayerZeroComposer
*/
interface ILayerZeroComposer {
/**
* @notice Composes a LayerZero message from an OApp.
* @dev To ensure non-reentrancy, implementers of this interface MUST assert msg.sender is the corresponding EndpointV2 contract (i.e., onlyEndpointV2).
* @param _from The address initiating the composition, typically the OApp where the lzReceive was called.
* @param _guid The unique identifier for the corresponding LayerZero src/dst tx.
* @param _message The composed message payload in bytes. NOT necessarily the same payload passed via lzReceive.
* @param _executor The address of the executor for the composed message.
* @param _extraData Additional arbitrary data in bytes passed by the entity who executes the lzCompose.
*/
function lzCompose(
address _from,
bytes32 _guid,
bytes calldata _message,
address _executor,
bytes calldata _extraData
) external payable;
}// 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;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
import { Origin } from "./ILayerZeroEndpointV2.sol";
interface ILayerZeroReceiver {
function allowInitializePath(Origin calldata _origin) external view returns (bool);
function nextNonce(uint32 _eid, bytes32 _sender) external view returns (uint64);
function lzReceive(
Origin calldata _origin,
bytes32 _guid,
bytes calldata _message,
address _executor,
bytes calldata _extraData
) external payable;
}// 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);
}// 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);
}// 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);
}// 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;
}// 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);
}// 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;
}// 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));
}
}// 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));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { IOAppOptionsType3, EnforcedOptionParam } from "@layerzerolabs/oapp-evm/contracts/oapp/interfaces/IOAppOptionsType3.sol";
/**
* @title OAppOptionsType3
* @dev Abstract contract implementing the IOAppOptionsType3 interface with type 3 options.
*/
abstract contract OAppOptionsType3Upgradeable is IOAppOptionsType3, OwnableUpgradeable {
struct OAppOptionsType3Storage {
// @dev The "msgType" should be defined in the child contract.
mapping(uint32 => mapping(uint16 => bytes)) enforcedOptions;
}
// keccak256(abi.encode(uint256(keccak256("layerzerov2.storage.oappoptionstype3")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OAPP_OPTIONS_TYPE_3_STORAGE_LOCATION =
0x8d2bda5d9f6ffb5796910376005392955773acee5548d0fcdb10e7c264ea0000;
uint16 internal constant OPTION_TYPE_3 = 3;
function _getOAppOptionsType3Storage() internal pure returns (OAppOptionsType3Storage storage $) {
assembly {
$.slot := OAPP_OPTIONS_TYPE_3_STORAGE_LOCATION
}
}
/**
* @dev Ownable is not initialized here on purpose. It should be initialized in the child contract to
* accommodate the different version of Ownable.
*/
function __OAppOptionsType3_init() internal onlyInitializing {}
function __OAppOptionsType3_init_unchained() internal onlyInitializing {}
function enforcedOptions(uint32 _eid, uint16 _msgType) public view returns (bytes memory) {
OAppOptionsType3Storage storage $ = _getOAppOptionsType3Storage();
return $.enforcedOptions[_eid][_msgType];
}
/**
* @dev Sets the enforced options for specific endpoint and message type combinations.
* @param _enforcedOptions An array of EnforcedOptionParam structures specifying enforced options.
*
* @dev Only the owner/admin of the OApp can call this function.
* @dev Provides a way for the OApp to enforce things like paying for PreCrime, AND/OR minimum dst lzReceive gas amounts etc.
* @dev These enforced options can vary as the potential options/execution on the remote may differ as per the msgType.
* eg. Amount of lzReceive() gas necessary to deliver a lzCompose() message adds overhead you dont want to pay
* if you are only making a standard LayerZero message ie. lzReceive() WITHOUT sendCompose().
*/
function setEnforcedOptions(EnforcedOptionParam[] calldata _enforcedOptions) public virtual onlyOwner {
OAppOptionsType3Storage storage $ = _getOAppOptionsType3Storage();
for (uint256 i = 0; i < _enforcedOptions.length; i++) {
// @dev Enforced options are only available for optionType 3, as type 1 and 2 dont support combining.
_assertOptionsType3(_enforcedOptions[i].options);
$.enforcedOptions[_enforcedOptions[i].eid][_enforcedOptions[i].msgType] = _enforcedOptions[i].options;
}
emit EnforcedOptionSet(_enforcedOptions);
}
/**
* @notice Combines options for a given endpoint and message type.
* @param _eid The endpoint ID.
* @param _msgType The OAPP message type.
* @param _extraOptions Additional options passed by the caller.
* @return options The combination of caller specified options AND enforced options.
*
* @dev If there is an enforced lzReceive option:
* - {gasLimit: 200k, msg.value: 1 ether} AND a caller supplies a lzReceive option: {gasLimit: 100k, msg.value: 0.5 ether}
* - The resulting options will be {gasLimit: 300k, msg.value: 1.5 ether} when the message is executed on the remote lzReceive() function.
* @dev This presence of duplicated options is handled off-chain in the verifier/executor.
*/
function combineOptions(
uint32 _eid,
uint16 _msgType,
bytes calldata _extraOptions
) public view virtual returns (bytes memory) {
OAppOptionsType3Storage storage $ = _getOAppOptionsType3Storage();
bytes memory enforced = $.enforcedOptions[_eid][_msgType];
// No enforced options, pass whatever the caller supplied, even if it's empty or legacy type 1/2 options.
if (enforced.length == 0) return _extraOptions;
// No caller options, return enforced
if (_extraOptions.length == 0) return enforced;
// @dev If caller provided _extraOptions, must be type 3 as its the ONLY type that can be combined.
if (_extraOptions.length >= 2) {
_assertOptionsType3(_extraOptions);
// @dev Remove the first 2 bytes containing the type from the _extraOptions and combine with enforced.
return bytes.concat(enforced, _extraOptions[2:]);
}
// No valid set of options was found.
revert InvalidOptions(_extraOptions);
}
/**
* @dev Internal function to assert that options are of type 3.
* @param _options The options to be checked.
*/
function _assertOptionsType3(bytes calldata _options) internal pure virtual {
uint16 optionsType = uint16(bytes2(_options[0:2]));
if (optionsType != OPTION_TYPE_3) revert InvalidOptions(_options);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { IOAppCore, ILayerZeroEndpointV2 } from "@layerzerolabs/oapp-evm/contracts/oapp/interfaces/IOAppCore.sol";
/**
* @title OAppCore
* @dev Abstract contract implementing the IOAppCore interface with basic OApp configurations.
*/
abstract contract OAppCoreUpgradeable is IOAppCore, OwnableUpgradeable {
struct OAppCoreStorage {
mapping(uint32 => bytes32) peers;
}
// keccak256(abi.encode(uint256(keccak256("layerzerov2.storage.oappcore")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OAPP_CORE_STORAGE_LOCATION =
0x72ab1bc1039b79dc4724ffca13de82c96834302d3c7e0d4252232d4b2dd8f900;
function _getOAppCoreStorage() internal pure returns (OAppCoreStorage storage $) {
assembly {
$.slot := OAPP_CORE_STORAGE_LOCATION
}
}
// The LayerZero endpoint associated with the given OApp
ILayerZeroEndpointV2 public immutable endpoint;
/**
* @dev Constructor to initialize the OAppCore with the provided endpoint and delegate.
* @param _endpoint The address of the LOCAL Layer Zero endpoint.
*/
constructor(address _endpoint) {
endpoint = ILayerZeroEndpointV2(_endpoint);
}
/**
* @dev Initializes the OAppCore with the provided delegate.
* @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
*
* @dev The delegate typically should be set as the owner of the contract.
* @dev Ownable is not initialized here on purpose. It should be initialized in the child contract to
* accommodate the different version of Ownable.
*/
function __OAppCore_init(address _delegate) internal onlyInitializing {
__OAppCore_init_unchained(_delegate);
}
function __OAppCore_init_unchained(address _delegate) internal onlyInitializing {
if (_delegate == address(0)) revert InvalidDelegate();
endpoint.setDelegate(_delegate);
}
/**
* @notice Returns the peer address (OApp instance) associated with a specific endpoint.
* @param _eid The endpoint ID.
* @return peer The address of the peer associated with the specified endpoint.
*/
function peers(uint32 _eid) public view override returns (bytes32) {
OAppCoreStorage storage $ = _getOAppCoreStorage();
return $.peers[_eid];
}
/**
* @notice Sets the peer address (OApp instance) for a corresponding endpoint.
* @param _eid The endpoint ID.
* @param _peer The address of the peer to be associated with the corresponding endpoint.
*
* @dev Only the owner/admin of the OApp can call this function.
* @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.
* @dev Set this to bytes32(0) to remove the peer address.
* @dev Peer is a bytes32 to accommodate non-evm chains.
*/
function setPeer(uint32 _eid, bytes32 _peer) public virtual onlyOwner {
OAppCoreStorage storage $ = _getOAppCoreStorage();
$.peers[_eid] = _peer;
emit PeerSet(_eid, _peer);
}
/**
* @notice Internal function to get the peer address associated with a specific endpoint; reverts if NOT set.
* ie. the peer is set to bytes32(0).
* @param _eid The endpoint ID.
* @return peer The address of the peer associated with the specified endpoint.
*/
function _getPeerOrRevert(uint32 _eid) internal view virtual returns (bytes32) {
OAppCoreStorage storage $ = _getOAppCoreStorage();
bytes32 peer = $.peers[_eid];
if (peer == bytes32(0)) revert NoPeer(_eid);
return peer;
}
/**
* @notice Sets the delegate address for the OApp.
* @param _delegate The address of the delegate to be set.
*
* @dev Only the owner/admin of the OApp can call this function.
* @dev Provides the ability for a delegate to set configs, on behalf of the OApp, directly on the Endpoint contract.
*/
function setDelegate(address _delegate) public onlyOwner {
endpoint.setDelegate(_delegate);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { IOAppReceiver, Origin } from "@layerzerolabs/oapp-evm/contracts/oapp/interfaces/IOAppReceiver.sol";
import { OAppCoreUpgradeable } from "./OAppCoreUpgradeable.sol";
/**
* @title OAppReceiver
* @dev Abstract contract implementing the ILayerZeroReceiver interface and extending OAppCore for OApp receivers.
*/
abstract contract OAppReceiverUpgradeable is IOAppReceiver, OAppCoreUpgradeable {
// Custom error message for when the caller is not the registered endpoint/
error OnlyEndpoint(address addr);
// @dev The version of the OAppReceiver implementation.
// @dev Version is bumped when changes are made to this contract.
uint64 internal constant RECEIVER_VERSION = 2;
/**
* @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
* @dev Ownable is not initialized here on purpose. It should be initialized in the child contract to
* accommodate the different version of Ownable.
*/
function __OAppReceiver_init(address _delegate) internal onlyInitializing {
__OAppCore_init(_delegate);
}
function __OAppReceiver_init_unchained() internal onlyInitializing {}
/**
* @notice Retrieves the OApp version information.
* @return senderVersion The version of the OAppSender.sol contract.
* @return receiverVersion The version of the OAppReceiver.sol contract.
*
* @dev Providing 0 as the default for OAppSender version. Indicates that the OAppSender is not implemented.
* ie. this is a RECEIVE only OApp.
* @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions.
*/
function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {
return (0, RECEIVER_VERSION);
}
/**
* @notice Indicates whether an address is an approved composeMsg sender to the Endpoint.
* @dev _origin The origin information containing the source endpoint and sender address.
* - srcEid: The source chain endpoint ID.
* - sender: The sender address on the src chain.
* - nonce: The nonce of the message.
* @dev _message The lzReceive payload.
* @param _sender The sender address.
* @return isSender Is a valid sender.
*
* @dev Applications can optionally choose to implement separate composeMsg senders that are NOT the bridging layer.
* @dev The default sender IS the OAppReceiver implementer.
*/
function isComposeMsgSender(
Origin calldata /*_origin*/,
bytes calldata /*_message*/,
address _sender
) public view virtual returns (bool) {
return _sender == address(this);
}
/**
* @notice Checks if the path initialization is allowed based on the provided origin.
* @param origin The origin information containing the source endpoint and sender address.
* @return Whether the path has been initialized.
*
* @dev This indicates to the endpoint that the OApp has enabled msgs for this particular path to be received.
* @dev This defaults to assuming if a peer has been set, its initialized.
* Can be overridden by the OApp if there is other logic to determine this.
*/
function allowInitializePath(Origin calldata origin) public view virtual returns (bool) {
return peers(origin.srcEid) == origin.sender;
}
/**
* @notice Retrieves the next nonce for a given source endpoint and sender address.
* @dev _srcEid The source endpoint ID.
* @dev _sender The sender address.
* @return nonce The next nonce.
*
* @dev The path nonce starts from 1. If 0 is returned it means that there is NO nonce ordered enforcement.
* @dev Is required by the off-chain executor to determine the OApp expects msg execution is ordered.
* @dev This is also enforced by the OApp.
* @dev By default this is NOT enabled. ie. nextNonce is hardcoded to return 0.
*/
function nextNonce(uint32, /*_srcEid*/ bytes32 /*_sender*/) public view virtual returns (uint64 nonce) {
return 0;
}
/**
* @dev Entry point for receiving messages or packets from the endpoint.
* @param _origin The origin information containing the source endpoint and sender address.
* - srcEid: The source chain endpoint ID.
* - sender: The sender address on the src chain.
* - nonce: The nonce of the message.
* @param _guid The unique identifier for the received LayerZero message.
* @param _message The payload of the received message.
* @param _executor The address of the executor for the received message.
* @param _extraData Additional arbitrary data provided by the corresponding executor.
*
* @dev Entry point for receiving msg/packet from the LayerZero endpoint.
*/
function lzReceive(
Origin calldata _origin,
bytes32 _guid,
bytes calldata _message,
address _executor,
bytes calldata _extraData
) public payable virtual {
// Ensures that only the endpoint can attempt to lzReceive() messages to this OApp.
if (address(endpoint) != msg.sender) revert OnlyEndpoint(msg.sender);
// Ensure that the sender matches the expected peer for the source endpoint.
if (_getPeerOrRevert(_origin.srcEid) != _origin.sender) revert OnlyPeer(_origin.srcEid, _origin.sender);
// Call the internal OApp implementation of lzReceive.
_lzReceive(_origin, _guid, _message, _executor, _extraData);
}
/**
* @dev Internal function to implement lzReceive logic without needing to copy the basic parameter validation.
*/
function _lzReceive(
Origin calldata _origin,
bytes32 _guid,
bytes calldata _message,
address _executor,
bytes calldata _extraData
) internal virtual;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { MessagingParams, MessagingFee, MessagingReceipt } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
import { OAppCoreUpgradeable } from "./OAppCoreUpgradeable.sol";
/**
* @title OAppSender
* @dev Abstract contract implementing the OAppSender functionality for sending messages to a LayerZero endpoint.
*/
abstract contract OAppSenderUpgradeable is OAppCoreUpgradeable {
using SafeERC20 for IERC20;
// Custom error messages
error NotEnoughNative(uint256 msgValue);
error LzTokenUnavailable();
// @dev The version of the OAppSender implementation.
// @dev Version is bumped when changes are made to this contract.
uint64 internal constant SENDER_VERSION = 1;
/**
* @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
* @dev Ownable is not initialized here on purpose. It should be initialized in the child contract to
* accommodate the different version of Ownable.
*/
function __OAppSender_init(address _delegate) internal onlyInitializing {
__OAppCore_init(_delegate);
}
function __OAppSender_init_unchained() internal onlyInitializing {}
/**
* @notice Retrieves the OApp version information.
* @return senderVersion The version of the OAppSender.sol contract.
* @return receiverVersion The version of the OAppReceiver.sol contract.
*
* @dev Providing 0 as the default for OAppReceiver version. Indicates that the OAppReceiver is not implemented.
* ie. this is a SEND only OApp.
* @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions
*/
function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {
return (SENDER_VERSION, 0);
}
/**
* @dev Internal function to interact with the LayerZero EndpointV2.quote() for fee calculation.
* @param _dstEid The destination endpoint ID.
* @param _message The message payload.
* @param _options Additional options for the message.
* @param _payInLzToken Flag indicating whether to pay the fee in LZ tokens.
* @return fee The calculated MessagingFee for the message.
* - nativeFee: The native fee for the message.
* - lzTokenFee: The LZ token fee for the message.
*/
function _quote(
uint32 _dstEid,
bytes memory _message,
bytes memory _options,
bool _payInLzToken
) internal view virtual returns (MessagingFee memory fee) {
return
endpoint.quote(
MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _payInLzToken),
address(this)
);
}
/**
* @dev Internal function to interact with the LayerZero EndpointV2.send() for sending a message.
* @param _dstEid The destination endpoint ID.
* @param _message The message payload.
* @param _options Additional options for the message.
* @param _fee The calculated LayerZero fee for the message.
* - nativeFee: The native fee.
* - lzTokenFee: The lzToken fee.
* @param _refundAddress The address to receive any excess fee values sent to the endpoint.
* @return receipt The receipt for the sent message.
* - guid: The unique identifier for the sent message.
* - nonce: The nonce of the sent message.
* - fee: The LayerZero fee incurred for the message.
*/
function _lzSend(
uint32 _dstEid,
bytes memory _message,
bytes memory _options,
MessagingFee memory _fee,
address _refundAddress
) internal virtual returns (MessagingReceipt memory receipt) {
// @dev Push corresponding fees to the endpoint, any excess is sent back to the _refundAddress from the endpoint.
uint256 messageValue = _payNative(_fee.nativeFee);
if (_fee.lzTokenFee > 0) _payLzToken(_fee.lzTokenFee);
return
// solhint-disable-next-line check-send-result
endpoint.send{ value: messageValue }(
MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _fee.lzTokenFee > 0),
_refundAddress
);
}
/**
* @dev Internal function to pay the native fee associated with the message.
* @param _nativeFee The native fee to be paid.
* @return nativeFee The amount of native currency paid.
*
* @dev If the OApp needs to initiate MULTIPLE LayerZero messages in a single transaction,
* this will need to be overridden because msg.value would contain multiple lzFees.
* @dev Should be overridden in the event the LayerZero endpoint requires a different native currency.
* @dev Some EVMs use an ERC20 as a method for paying transactions/gasFees.
* @dev The endpoint is EITHER/OR, ie. it will NOT support both types of native payment at a time.
*/
function _payNative(uint256 _nativeFee) internal virtual returns (uint256 nativeFee) {
if (msg.value != _nativeFee) revert NotEnoughNative(msg.value);
return _nativeFee;
}
/**
* @dev Internal function to pay the LZ token fee associated with the message.
* @param _lzTokenFee The LZ token fee to be paid.
*
* @dev If the caller is trying to pay in the specified lzToken, then the lzTokenFee is passed to the endpoint.
* @dev Any excess sent, is passed back to the specified _refundAddress in the _lzSend().
*/
function _payLzToken(uint256 _lzTokenFee) internal virtual {
// @dev Cannot cache the token because it is not immutable in the endpoint.
address lzToken = endpoint.lzToken();
if (lzToken == address(0)) revert LzTokenUnavailable();
// Pay LZ token fee by sending tokens to the endpoint.
IERC20(lzToken).safeTransferFrom(msg.sender, address(endpoint), _lzTokenFee);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// @dev Import the 'MessagingFee' and 'MessagingReceipt' so it's exposed to OApp implementers
// solhint-disable-next-line no-unused-import
import { OAppSenderUpgradeable, MessagingFee, MessagingReceipt } from "./OAppSenderUpgradeable.sol";
// @dev Import the 'Origin' so it's exposed to OApp implementers
// solhint-disable-next-line no-unused-import
import { OAppReceiverUpgradeable, Origin } from "./OAppReceiverUpgradeable.sol";
import { OAppCoreUpgradeable } from "./OAppCoreUpgradeable.sol";
/**
* @title OApp
* @dev Abstract contract serving as the base for OApp implementation, combining OAppSender and OAppReceiver functionality.
*/
abstract contract OAppUpgradeable is OAppSenderUpgradeable, OAppReceiverUpgradeable {
/**
* @dev Constructor to initialize the OApp with the provided endpoint and owner.
* @param _endpoint The address of the LOCAL LayerZero endpoint.
*/
constructor(address _endpoint) OAppCoreUpgradeable(_endpoint) {}
/**
* @dev Initializes the OApp with the provided delegate.
* @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
*
* @dev The delegate typically should be set as the owner of the contract.
* @dev Ownable is not initialized here on purpose. It should be initialized in the child contract to
* accommodate the different version of Ownable.
*/
function __OApp_init(address _delegate) internal onlyInitializing {
__OAppCore_init(_delegate);
__OAppReceiver_init_unchained();
__OAppSender_init_unchained();
}
function __OApp_init_unchained() internal onlyInitializing {}
/**
* @notice Retrieves the OApp version information.
* @return senderVersion The version of the OAppSender.sol implementation.
* @return receiverVersion The version of the OAppReceiver.sol implementation.
*/
function oAppVersion()
public
pure
virtual
override(OAppSenderUpgradeable, OAppReceiverUpgradeable)
returns (uint64 senderVersion, uint64 receiverVersion)
{
return (SENDER_VERSION, RECEIVER_VERSION);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import { IPreCrime } from "@layerzerolabs/oapp-evm/contracts/precrime/interfaces/IPreCrime.sol";
import { IOAppPreCrimeSimulator, InboundPacket, Origin } from "@layerzerolabs/oapp-evm/contracts/precrime/interfaces/IOAppPreCrimeSimulator.sol";
/**
* @title OAppPreCrimeSimulator
* @dev Abstract contract serving as the base for preCrime simulation functionality in an OApp.
*/
abstract contract OAppPreCrimeSimulatorUpgradeable is IOAppPreCrimeSimulator, OwnableUpgradeable {
struct OAppPreCrimeSimulatorStorage {
// The address of the preCrime implementation.
address preCrime;
}
// keccak256(abi.encode(uint256(keccak256("layerzerov2.storage.oappprecrimesimulator")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OAPP_PRE_CRIME_SIMULATOR_STORAGE_LOCATION =
0xefb041d771d6daaa55702fff6eb740d63ba559a75d2d1d3e151c78ff2480b600;
function _getOAppPreCrimeSimulatorStorage() internal pure returns (OAppPreCrimeSimulatorStorage storage $) {
assembly {
$.slot := OAPP_PRE_CRIME_SIMULATOR_STORAGE_LOCATION
}
}
/**
* @dev Ownable is not initialized here on purpose. It should be initialized in the child contract to
* accommodate the different version of Ownable.
*/
function __OAppPreCrimeSimulator_init() internal onlyInitializing {}
function __OAppPreCrimeSimulator_init_unchained() internal onlyInitializing {}
function preCrime() external view override returns (address) {
OAppPreCrimeSimulatorStorage storage $ = _getOAppPreCrimeSimulatorStorage();
return $.preCrime;
}
/**
* @dev Retrieves the address of the OApp contract.
* @return The address of the OApp contract.
*
* @dev The simulator contract is the base contract for the OApp by default.
* @dev If the simulator is a separate contract, override this function.
*/
function oApp() external view virtual returns (address) {
return address(this);
}
/**
* @dev Sets the preCrime contract address.
* @param _preCrime The address of the preCrime contract.
*/
function setPreCrime(address _preCrime) public virtual onlyOwner {
OAppPreCrimeSimulatorStorage storage $ = _getOAppPreCrimeSimulatorStorage();
$.preCrime = _preCrime;
emit PreCrimeSet(_preCrime);
}
/**
* @dev Interface for pre-crime simulations. Always reverts at the end with the simulation results.
* @param _packets An array of InboundPacket objects representing received packets to be delivered.
*
* @dev WARNING: MUST revert at the end with the simulation results.
* @dev Gives the preCrime implementation the ability to mock sending packets to the lzReceive function,
* WITHOUT actually executing them.
*/
function lzReceiveAndRevert(InboundPacket[] calldata _packets) public payable virtual {
for (uint256 i = 0; i < _packets.length; i++) {
InboundPacket calldata packet = _packets[i];
// Ignore packets that are not from trusted peers.
if (!isPeer(packet.origin.srcEid, packet.origin.sender)) continue;
// @dev Because a verifier is calling this function, it doesnt have access to executor params:
// - address _executor
// - bytes calldata _extraData
// preCrime will NOT work for OApps that rely on these two parameters inside of their _lzReceive().
// They are instead stubbed to default values, address(0) and bytes("")
// @dev Calling this.lzReceiveSimulate removes ability for assembly return 0 callstack exit,
// which would cause the revert to be ignored.
this.lzReceiveSimulate{ value: packet.value }(
packet.origin,
packet.guid,
packet.message,
packet.executor,
packet.extraData
);
}
// @dev Revert with the simulation results. msg.sender must implement IPreCrime.buildSimulationResult().
revert SimulationResult(IPreCrime(msg.sender).buildSimulationResult());
}
/**
* @dev Is effectively an internal function because msg.sender must be address(this).
* Allows resetting the call stack for 'internal' calls.
* @param _origin The origin information containing the source endpoint and sender address.
* - srcEid: The source chain endpoint ID.
* - sender: The sender address on the src chain.
* - nonce: The nonce of the message.
* @param _guid The unique identifier of the packet.
* @param _message The message payload of the packet.
* @param _executor The executor address for the packet.
* @param _extraData Additional data for the packet.
*/
function lzReceiveSimulate(
Origin calldata _origin,
bytes32 _guid,
bytes calldata _message,
address _executor,
bytes calldata _extraData
) external payable virtual {
// @dev Ensure ONLY can be called 'internally'.
if (msg.sender != address(this)) revert OnlySelf();
_lzReceiveSimulate(_origin, _guid, _message, _executor, _extraData);
}
/**
* @dev Internal function to handle the OAppPreCrimeSimulator simulated receive.
* @param _origin The origin information.
* - srcEid: The source chain endpoint ID.
* - sender: The sender address from the src chain.
* - nonce: The nonce of the LayerZero message.
* @param _guid The GUID of the LayerZero message.
* @param _message The LayerZero message.
* @param _executor The address of the off-chain executor.
* @param _extraData Arbitrary data passed by the msg executor.
*
* @dev Enables the preCrime simulator to mock sending lzReceive() messages,
* routes the msg down from the OAppPreCrimeSimulator, and back up to the OAppReceiver.
*/
function _lzReceiveSimulate(
Origin calldata _origin,
bytes32 _guid,
bytes calldata _message,
address _executor,
bytes calldata _extraData
) internal virtual;
/**
* @dev checks if the specified peer is considered 'trusted' by the OApp.
* @param _eid The endpoint Id to check.
* @param _peer The peer to check.
* @return Whether the peer passed is considered 'trusted' by the OApp.
*/
function isPeer(uint32 _eid, bytes32 _peer) public view virtual returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { ILayerZeroComposer } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroComposer.sol";
/**
* @title IOAppComposer
* @dev This interface defines the OApp Composer, allowing developers to inherit only the OApp package without the protocol.
*/
// solhint-disable-next-line no-empty-blocks
interface IOAppComposer is ILayerZeroComposer {}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { ILayerZeroEndpointV2 } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
/**
* @title IOAppCore
*/
interface IOAppCore {
// Custom error messages
error OnlyPeer(uint32 eid, bytes32 sender);
error NoPeer(uint32 eid);
error InvalidEndpointCall();
error InvalidDelegate();
// Event emitted when a peer (OApp) is set for a corresponding endpoint
event PeerSet(uint32 eid, bytes32 peer);
/**
* @notice Retrieves the OApp version information.
* @return senderVersion The version of the OAppSender.sol contract.
* @return receiverVersion The version of the OAppReceiver.sol contract.
*/
function oAppVersion() external view returns (uint64 senderVersion, uint64 receiverVersion);
/**
* @notice Retrieves the LayerZero endpoint associated with the OApp.
* @return iEndpoint The LayerZero endpoint as an interface.
*/
function endpoint() external view returns (ILayerZeroEndpointV2 iEndpoint);
/**
* @notice Retrieves the peer (OApp) associated with a corresponding endpoint.
* @param _eid The endpoint ID.
* @return peer The peer address (OApp instance) associated with the corresponding endpoint.
*/
function peers(uint32 _eid) external view returns (bytes32 peer);
/**
* @notice Sets the peer address (OApp instance) for a corresponding endpoint.
* @param _eid The endpoint ID.
* @param _peer The address of the peer to be associated with the corresponding endpoint.
*/
function setPeer(uint32 _eid, bytes32 _peer) external;
/**
* @notice Sets the delegate address for the OApp Core.
* @param _delegate The address of the delegate to be set.
*/
function setDelegate(address _delegate) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @title IOAppMsgInspector
* @dev Interface for the OApp Message Inspector, allowing examination of message and options contents.
*/
interface IOAppMsgInspector {
// Custom error message for inspection failure
error InspectionFailed(bytes message, bytes options);
/**
* @notice Allows the inspector to examine LayerZero message contents and optionally throw a revert if invalid.
* @param _message The message payload to be inspected.
* @param _options Additional options or parameters for inspection.
* @return valid A boolean indicating whether the inspection passed (true) or failed (false).
*
* @dev Optionally done as a revert, OR use the boolean provided to handle the failure.
*/
function inspect(bytes calldata _message, bytes calldata _options) external view returns (bool valid);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @dev Struct representing enforced option parameters.
*/
struct EnforcedOptionParam {
uint32 eid; // Endpoint ID
uint16 msgType; // Message Type
bytes options; // Additional options
}
/**
* @title IOAppOptionsType3
* @dev Interface for the OApp with Type 3 Options, allowing the setting and combining of enforced options.
*/
interface IOAppOptionsType3 {
// Custom error message for invalid options
error InvalidOptions(bytes options);
// Event emitted when enforced options are set
event EnforcedOptionSet(EnforcedOptionParam[] _enforcedOptions);
/**
* @notice Sets enforced options for specific endpoint and message type combinations.
* @param _enforcedOptions An array of EnforcedOptionParam structures specifying enforced options.
*/
function setEnforcedOptions(EnforcedOptionParam[] calldata _enforcedOptions) external;
/**
* @notice Combines options for a given endpoint and message type.
* @param _eid The endpoint ID.
* @param _msgType The OApp message type.
* @param _extraOptions Additional options passed by the caller.
* @return options The combination of caller specified options AND enforced options.
*/
function combineOptions(
uint32 _eid,
uint16 _msgType,
bytes calldata _extraOptions
) external view returns (bytes memory options);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { ILayerZeroReceiver, Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroReceiver.sol";
interface IOAppReceiver is ILayerZeroReceiver {
/**
* @notice Indicates whether an address is an approved composeMsg sender to the Endpoint.
* @param _origin The origin information containing the source endpoint and sender address.
* - srcEid: The source chain endpoint ID.
* - sender: The sender address on the src chain.
* - nonce: The nonce of the message.
* @param _message The lzReceive payload.
* @param _sender The sender address.
* @return isSender Is a valid sender.
*
* @dev Applications can optionally choose to implement a separate composeMsg sender that is NOT the bridging layer.
* @dev The default sender IS the OAppReceiver implementer.
*/
function isComposeMsgSender(
Origin calldata _origin,
bytes calldata _message,
address _sender
) external view returns (bool isSender);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IOAppCore, ILayerZeroEndpointV2 } from "./interfaces/IOAppCore.sol";
/**
* @title OAppCore
* @dev Abstract contract implementing the IOAppCore interface with basic OApp configurations.
*/
abstract contract OAppCore is IOAppCore, Ownable {
// The LayerZero endpoint associated with the given OApp
ILayerZeroEndpointV2 public immutable endpoint;
// Mapping to store peers associated with corresponding endpoints
mapping(uint32 eid => bytes32 peer) public peers;
/**
* @dev Constructor to initialize the OAppCore with the provided endpoint and delegate.
* @param _endpoint The address of the LOCAL Layer Zero endpoint.
* @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
*
* @dev The delegate typically should be set as the owner of the contract.
*/
constructor(address _endpoint, address _delegate) {
endpoint = ILayerZeroEndpointV2(_endpoint);
if (_delegate == address(0)) revert InvalidDelegate();
endpoint.setDelegate(_delegate);
}
/**
* @notice Sets the peer address (OApp instance) for a corresponding endpoint.
* @param _eid The endpoint ID.
* @param _peer The address of the peer to be associated with the corresponding endpoint.
*
* @dev Only the owner/admin of the OApp can call this function.
* @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.
* @dev Set this to bytes32(0) to remove the peer address.
* @dev Peer is a bytes32 to accommodate non-evm chains.
*/
function setPeer(uint32 _eid, bytes32 _peer) public virtual onlyOwner {
_setPeer(_eid, _peer);
}
/**
* @notice Sets the peer address (OApp instance) for a corresponding endpoint.
* @param _eid The endpoint ID.
* @param _peer The address of the peer to be associated with the corresponding endpoint.
*
* @dev Indicates that the peer is trusted to send LayerZero messages to this OApp.
* @dev Set this to bytes32(0) to remove the peer address.
* @dev Peer is a bytes32 to accommodate non-evm chains.
*/
function _setPeer(uint32 _eid, bytes32 _peer) internal virtual {
peers[_eid] = _peer;
emit PeerSet(_eid, _peer);
}
/**
* @notice Internal function to get the peer address associated with a specific endpoint; reverts if NOT set.
* ie. the peer is set to bytes32(0).
* @param _eid The endpoint ID.
* @return peer The address of the peer associated with the specified endpoint.
*/
function _getPeerOrRevert(uint32 _eid) internal view virtual returns (bytes32) {
bytes32 peer = peers[_eid];
if (peer == bytes32(0)) revert NoPeer(_eid);
return peer;
}
/**
* @notice Sets the delegate address for the OApp.
* @param _delegate The address of the delegate to be set.
*
* @dev Only the owner/admin of the OApp can call this function.
* @dev Provides the ability for a delegate to set configs, on behalf of the OApp, directly on the Endpoint contract.
*/
function setDelegate(address _delegate) public onlyOwner {
endpoint.setDelegate(_delegate);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { MessagingParams, MessagingFee, MessagingReceipt } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
import { OAppCore } from "./OAppCore.sol";
/**
* @title OAppSender
* @dev Abstract contract implementing the OAppSender functionality for sending messages to a LayerZero endpoint.
*/
abstract contract OAppSender is OAppCore {
using SafeERC20 for IERC20;
// Custom error messages
error NotEnoughNative(uint256 msgValue);
error LzTokenUnavailable();
// @dev The version of the OAppSender implementation.
// @dev Version is bumped when changes are made to this contract.
uint64 internal constant SENDER_VERSION = 1;
/**
* @notice Retrieves the OApp version information.
* @return senderVersion The version of the OAppSender.sol contract.
* @return receiverVersion The version of the OAppReceiver.sol contract.
*
* @dev Providing 0 as the default for OAppReceiver version. Indicates that the OAppReceiver is not implemented.
* ie. this is a SEND only OApp.
* @dev If the OApp uses both OAppSender and OAppReceiver, then this needs to be override returning the correct versions
*/
function oAppVersion() public view virtual returns (uint64 senderVersion, uint64 receiverVersion) {
return (SENDER_VERSION, 0);
}
/**
* @dev Internal function to interact with the LayerZero EndpointV2.quote() for fee calculation.
* @param _dstEid The destination endpoint ID.
* @param _message The message payload.
* @param _options Additional options for the message.
* @param _payInLzToken Flag indicating whether to pay the fee in LZ tokens.
* @return fee The calculated MessagingFee for the message.
* - nativeFee: The native fee for the message.
* - lzTokenFee: The LZ token fee for the message.
*/
function _quote(
uint32 _dstEid,
bytes memory _message,
bytes memory _options,
bool _payInLzToken
) internal view virtual returns (MessagingFee memory fee) {
return
endpoint.quote(
MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _payInLzToken),
address(this)
);
}
/**
* @dev Internal function to interact with the LayerZero EndpointV2.send() for sending a message.
* @param _dstEid The destination endpoint ID.
* @param _message The message payload.
* @param _options Additional options for the message.
* @param _fee The calculated LayerZero fee for the message.
* - nativeFee: The native fee.
* - lzTokenFee: The lzToken fee.
* @param _refundAddress The address to receive any excess fee values sent to the endpoint.
* @return receipt The receipt for the sent message.
* - guid: The unique identifier for the sent message.
* - nonce: The nonce of the sent message.
* - fee: The LayerZero fee incurred for the message.
*/
function _lzSend(
uint32 _dstEid,
bytes memory _message,
bytes memory _options,
MessagingFee memory _fee,
address _refundAddress
) internal virtual returns (MessagingReceipt memory receipt) {
// @dev Push corresponding fees to the endpoint, any excess is sent back to the _refundAddress from the endpoint.
uint256 messageValue = _payNative(_fee.nativeFee);
if (_fee.lzTokenFee > 0) _payLzToken(_fee.lzTokenFee);
return
// solhint-disable-next-line check-send-result
endpoint.send{ value: messageValue }(
MessagingParams(_dstEid, _getPeerOrRevert(_dstEid), _message, _options, _fee.lzTokenFee > 0),
_refundAddress
);
}
/**
* @dev Internal function to pay the native fee associated with the message.
* @param _nativeFee The native fee to be paid.
* @return nativeFee The amount of native currency paid.
*
* @dev If the OApp needs to initiate MULTIPLE LayerZero messages in a single transaction,
* this will need to be overridden because msg.value would contain multiple lzFees.
* @dev Should be overridden in the event the LayerZero endpoint requires a different native currency.
* @dev Some EVMs use an ERC20 as a method for paying transactions/gasFees.
* @dev The endpoint is EITHER/OR, ie. it will NOT support both types of native payment at a time.
*/
function _payNative(uint256 _nativeFee) internal virtual returns (uint256 nativeFee) {
if (msg.value != _nativeFee) revert NotEnoughNative(msg.value);
return _nativeFee;
}
/**
* @dev Internal function to pay the LZ token fee associated with the message.
* @param _lzTokenFee The LZ token fee to be paid.
*
* @dev If the caller is trying to pay in the specified lzToken, then the lzTokenFee is passed to the endpoint.
* @dev Any excess sent, is passed back to the specified _refundAddress in the _lzSend().
*/
function _payLzToken(uint256 _lzTokenFee) internal virtual {
// @dev Cannot cache the token because it is not immutable in the endpoint.
address lzToken = endpoint.lzToken();
if (lzToken == address(0)) revert LzTokenUnavailable();
// Pay LZ token fee by sending tokens to the endpoint.
IERC20(lzToken).safeTransferFrom(msg.sender, address(endpoint), _lzTokenFee);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// @dev Import the Origin so it's exposed to OAppPreCrimeSimulator implementers.
// solhint-disable-next-line no-unused-import
import { InboundPacket, Origin } from "../libs/Packet.sol";
/**
* @title IOAppPreCrimeSimulator Interface
* @dev Interface for the preCrime simulation functionality in an OApp.
*/
interface IOAppPreCrimeSimulator {
// @dev simulation result used in PreCrime implementation
error SimulationResult(bytes result);
error OnlySelf();
/**
* @dev Emitted when the preCrime contract address is set.
* @param preCrimeAddress The address of the preCrime contract.
*/
event PreCrimeSet(address preCrimeAddress);
/**
* @dev Retrieves the address of the preCrime contract implementation.
* @return The address of the preCrime contract.
*/
function preCrime() external view returns (address);
/**
* @dev Retrieves the address of the OApp contract.
* @return The address of the OApp contract.
*/
function oApp() external view returns (address);
/**
* @dev Sets the preCrime contract address.
* @param _preCrime The address of the preCrime contract.
*/
function setPreCrime(address _preCrime) external;
/**
* @dev Mocks receiving a packet, then reverts with a series of data to infer the state/result.
* @param _packets An array of LayerZero InboundPacket objects representing received packets.
*/
function lzReceiveAndRevert(InboundPacket[] calldata _packets) external payable;
/**
* @dev checks if the specified peer is considered 'trusted' by the OApp.
* @param _eid The endpoint Id to check.
* @param _peer The peer to check.
* @return Whether the peer passed is considered 'trusted' by the OApp.
*/
function isPeer(uint32 _eid, bytes32 _peer) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
struct PreCrimePeer {
uint32 eid;
bytes32 preCrime;
bytes32 oApp;
}
// TODO not done yet
interface IPreCrime {
error OnlyOffChain();
// for simulate()
error PacketOversize(uint256 max, uint256 actual);
error PacketUnsorted();
error SimulationFailed(bytes reason);
// for preCrime()
error SimulationResultNotFound(uint32 eid);
error InvalidSimulationResult(uint32 eid, bytes reason);
error CrimeFound(bytes crime);
function getConfig(bytes[] calldata _packets, uint256[] calldata _packetMsgValues) external returns (bytes memory);
function simulate(
bytes[] calldata _packets,
uint256[] calldata _packetMsgValues
) external payable returns (bytes memory);
function buildSimulationResult() external view returns (bytes memory);
function preCrime(
bytes[] calldata _packets,
uint256[] calldata _packetMsgValues,
bytes[] calldata _simulations
) external;
function version() external view returns (uint64 major, uint8 minor);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { Origin } from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
import { PacketV1Codec } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/PacketV1Codec.sol";
/**
* @title InboundPacket
* @dev Structure representing an inbound packet received by the contract.
*/
struct InboundPacket {
Origin origin; // Origin information of the packet.
uint32 dstEid; // Destination endpointId of the packet.
address receiver; // Receiver address for the packet.
bytes32 guid; // Unique identifier of the packet.
uint256 value; // msg.value of the packet.
address executor; // Executor address for the packet.
bytes message; // Message payload of the packet.
bytes extraData; // Additional arbitrary data for the packet.
}
/**
* @title PacketDecoder
* @dev Library for decoding LayerZero packets.
*/
library PacketDecoder {
using PacketV1Codec for bytes;
/**
* @dev Decode an inbound packet from the given packet data.
* @param _packet The packet data to decode.
* @return packet An InboundPacket struct representing the decoded packet.
*/
function decode(bytes calldata _packet) internal pure returns (InboundPacket memory packet) {
packet.origin = Origin(_packet.srcEid(), _packet.sender(), _packet.nonce());
packet.dstEid = _packet.dstEid();
packet.receiver = _packet.receiverB20();
packet.guid = _packet.guid();
packet.message = _packet.message();
}
/**
* @dev Decode multiple inbound packets from the given packet data and associated message values.
* @param _packets An array of packet data to decode.
* @param _packetMsgValues An array of associated message values for each packet.
* @return packets An array of InboundPacket structs representing the decoded packets.
*/
function decode(
bytes[] calldata _packets,
uint256[] memory _packetMsgValues
) internal pure returns (InboundPacket[] memory packets) {
packets = new InboundPacket[](_packets.length);
for (uint256 i = 0; i < _packets.length; i++) {
bytes calldata packet = _packets[i];
packets[i] = PacketDecoder.decode(packet);
// @dev Allows the verifier to specify the msg.value that gets passed in lzReceive.
packets[i].value = _packetMsgValues[i];
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { OAppUpgradeable, Origin } from "@layerzerolabs/oapp-evm-upgradeable/contracts/oapp/OAppUpgradeable.sol";
import { OAppOptionsType3Upgradeable } from "@layerzerolabs/oapp-evm-upgradeable/contracts/oapp/libs/OAppOptionsType3Upgradeable.sol";
import { IOAppMsgInspector } from "@layerzerolabs/oapp-evm/contracts/oapp/interfaces/IOAppMsgInspector.sol";
import { OAppPreCrimeSimulatorUpgradeable } from "@layerzerolabs/oapp-evm-upgradeable/contracts/precrime/OAppPreCrimeSimulatorUpgradeable.sol";
import { IOFT, SendParam, OFTLimit, OFTReceipt, OFTFeeDetail, MessagingReceipt, MessagingFee } from "@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol";
import { OFTMsgCodec } from "@layerzerolabs/oft-evm/contracts/libs/OFTMsgCodec.sol";
import { OFTComposeMsgCodec } from "@layerzerolabs/oft-evm/contracts/libs/OFTComposeMsgCodec.sol";
/**
* @title OFTCore
* @dev Abstract contract for the OftChain (OFT) token.
*/
abstract contract OFTCoreUpgradeable is
IOFT,
OAppUpgradeable,
OAppPreCrimeSimulatorUpgradeable,
OAppOptionsType3Upgradeable
{
using OFTMsgCodec for bytes;
using OFTMsgCodec for bytes32;
struct OFTCoreStorage {
// Address of an optional contract to inspect both 'message' and 'options'
address msgInspector;
}
// keccak256(abi.encode(uint256(keccak256("layerzerov2.storage.oftcore")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OFT_CORE_STORAGE_LOCATION =
0x41db8a78b0206aba5c54bcbfc2bda0d84082a84eb88e680379a57b9e9f653c00;
// @notice Provides a conversion rate when swapping between denominations of SD and LD
// - shareDecimals == SD == shared Decimals
// - localDecimals == LD == local decimals
// @dev Considers that tokens have different decimal amounts on various chains.
// @dev eg.
// For a token
// - locally with 4 decimals --> 1.2345 => uint(12345)
// - remotely with 2 decimals --> 1.23 => uint(123)
// - The conversion rate would be 10 ** (4 - 2) = 100
// @dev If you want to send 1.2345 -> (uint 12345), you CANNOT represent that value on the remote,
// you can only display 1.23 -> uint(123).
// @dev To preserve the dust that would otherwise be lost on that conversion,
// we need to unify a denomination that can be represented on ALL chains inside of the OFT mesh
uint256 public immutable decimalConversionRate;
// @notice Msg types that are used to identify the various OFT operations.
// @dev This can be extended in child contracts for non-default oft operations
// @dev These values are used in things like combineOptions() in OAppOptionsType3.sol.
uint16 public constant SEND = 1;
uint16 public constant SEND_AND_CALL = 2;
event MsgInspectorSet(address inspector);
function _getOFTCoreStorage() internal pure returns (OFTCoreStorage storage $) {
assembly {
$.slot := OFT_CORE_STORAGE_LOCATION
}
}
/**
* @dev Constructor.
* @param _localDecimals The decimals of the token on the local chain (this chain).
* @param _endpoint The address of the LayerZero endpoint.
*/
constructor(uint8 _localDecimals, address _endpoint) OAppUpgradeable(_endpoint) {
if (_localDecimals < sharedDecimals()) revert InvalidLocalDecimals();
decimalConversionRate = 10 ** (_localDecimals - sharedDecimals());
}
/**
* @notice Retrieves interfaceID and the version of the OFT.
* @return interfaceId The interface ID.
* @return version The version.
*
* @dev interfaceId: This specific interface ID is '0x02e49c2c'.
* @dev version: Indicates a cross-chain compatible msg encoding with other OFTs.
* @dev If a new feature is added to the OFT cross-chain msg encoding, the version will be incremented.
* ie. localOFT version(x,1) CAN send messages to remoteOFT version(x,1)
*/
function oftVersion() external pure virtual returns (bytes4 interfaceId, uint64 version) {
return (type(IOFT).interfaceId, 1);
}
/**
* @dev Initializes the OFTCore contract.
* @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
*
* @dev The delegate typically should be set as the owner of the contract.
* @dev Ownable is not initialized here on purpose. It should be initialized in the child contract to
* accommodate the different version of Ownable.
*/
function __OFTCore_init(address _delegate) internal onlyInitializing {
__OApp_init(_delegate);
__OAppPreCrimeSimulator_init();
__OAppOptionsType3_init();
}
function __OFTCore_init_unchained() internal onlyInitializing {}
function msgInspector() public view returns (address) {
OFTCoreStorage storage $ = _getOFTCoreStorage();
return $.msgInspector;
}
/**
* @dev Retrieves the shared decimals of the OFT.
* @return The shared decimals of the OFT.
*
* @dev Sets an implicit cap on the amount of tokens, over uint64.max() will need some sort of outbound cap / totalSupply cap
* Lowest common decimal denominator between chains.
* Defaults to 6 decimal places to provide up to 18,446,744,073,709.551615 units (max uint64).
* For tokens exceeding this totalSupply(), they will need to override the sharedDecimals function with something smaller.
* ie. 4 sharedDecimals would be 1,844,674,407,370,955.1615
*/
function sharedDecimals() public pure virtual returns (uint8) {
return 6;
}
/**
* @dev Sets the message inspector address for the OFT.
* @param _msgInspector The address of the message inspector.
*
* @dev This is an optional contract that can be used to inspect both 'message' and 'options'.
* @dev Set it to address(0) to disable it, or set it to a contract address to enable it.
*/
function setMsgInspector(address _msgInspector) public virtual onlyOwner {
OFTCoreStorage storage $ = _getOFTCoreStorage();
$.msgInspector = _msgInspector;
emit MsgInspectorSet(_msgInspector);
}
/**
* @notice Provides a quote for OFT-related operations.
* @param _sendParam The parameters for the send operation.
* @return oftLimit The OFT limit information.
* @return oftFeeDetails The details of OFT fees.
* @return oftReceipt The OFT receipt information.
*/
function quoteOFT(
SendParam calldata _sendParam
)
external
view
virtual
returns (OFTLimit memory oftLimit, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory oftReceipt)
{
uint256 minAmountLD = 0; // Unused in the default implementation.
uint256 maxAmountLD = type(uint64).max; // Unused in the default implementation.
oftLimit = OFTLimit(minAmountLD, maxAmountLD);
// Unused in the default implementation; reserved for future complex fee details.
oftFeeDetails = new OFTFeeDetail[](0);
// @dev This is the same as the send() operation, but without the actual send.
// - amountSentLD is the amount in local decimals that would be sent from the sender.
// - amountReceivedLD is the amount in local decimals that will be credited to the recipient on the remote OFT instance.
// @dev The amountSentLD MIGHT not equal the amount the user actually receives. HOWEVER, the default does.
(uint256 amountSentLD, uint256 amountReceivedLD) = _debitView(
_sendParam.amountLD,
_sendParam.minAmountLD,
_sendParam.dstEid
);
oftReceipt = OFTReceipt(amountSentLD, amountReceivedLD);
}
/**
* @notice Provides a quote for the send() operation.
* @param _sendParam The parameters for the send() operation.
* @param _payInLzToken Flag indicating whether the caller is paying in the LZ token.
* @return msgFee The calculated LayerZero messaging fee from the send() operation.
*
* @dev MessagingFee: LayerZero msg fee
* - nativeFee: The native fee.
* - lzTokenFee: The lzToken fee.
*/
function quoteSend(
SendParam calldata _sendParam,
bool _payInLzToken
) external view virtual returns (MessagingFee memory msgFee) {
// @dev mock the amount to receive, this is the same operation used in the send().
// The quote is as similar as possible to the actual send() operation.
(, uint256 amountReceivedLD) = _debitView(_sendParam.amountLD, _sendParam.minAmountLD, _sendParam.dstEid);
// @dev Builds the options and OFT message to quote in the endpoint.
(bytes memory message, bytes memory options) = _buildMsgAndOptions(_sendParam, amountReceivedLD);
// @dev Calculates the LayerZero fee for the send() operation.
return _quote(_sendParam.dstEid, message, options, _payInLzToken);
}
/**
* @dev Executes the send operation.
* @param _sendParam The parameters for the send operation.
* @param _fee The calculated fee for the send() operation.
* - nativeFee: The native fee.
* - lzTokenFee: The lzToken fee.
* @param _refundAddress The address to receive any excess funds.
* @return msgReceipt The receipt for the send operation.
* @return oftReceipt The OFT receipt information.
*
* @dev MessagingReceipt: LayerZero msg receipt
* - guid: The unique identifier for the sent message.
* - nonce: The nonce of the sent message.
* - fee: The LayerZero fee incurred for the message.
*/
function send(
SendParam calldata _sendParam,
MessagingFee calldata _fee,
address _refundAddress
) external payable virtual returns (MessagingReceipt memory msgReceipt, OFTReceipt memory oftReceipt) {
// @dev Applies the token transfers regarding this send() operation.
// - amountSentLD is the amount in local decimals that was ACTUALLY sent/debited from the sender.
// - amountReceivedLD is the amount in local decimals that will be received/credited to the recipient on the remote OFT instance.
(uint256 amountSentLD, uint256 amountReceivedLD) = _debit(
msg.sender,
_sendParam.amountLD,
_sendParam.minAmountLD,
_sendParam.dstEid
);
// @dev Builds the options and OFT message to quote in the endpoint.
(bytes memory message, bytes memory options) = _buildMsgAndOptions(_sendParam, amountReceivedLD);
// @dev Sends the message to the LayerZero endpoint and returns the LayerZero msg receipt.
msgReceipt = _lzSend(_sendParam.dstEid, message, options, _fee, _refundAddress);
// @dev Formulate the OFT receipt.
oftReceipt = OFTReceipt(amountSentLD, amountReceivedLD);
emit OFTSent(msgReceipt.guid, _sendParam.dstEid, msg.sender, amountSentLD, amountReceivedLD);
}
/**
* @dev Internal function to build the message and options.
* @param _sendParam The parameters for the send() operation.
* @param _amountLD The amount in local decimals.
* @return message The encoded message.
* @return options The encoded options.
*/
function _buildMsgAndOptions(
SendParam calldata _sendParam,
uint256 _amountLD
) internal view virtual returns (bytes memory message, bytes memory options) {
bool hasCompose;
// @dev This generated message has the msg.sender encoded into the payload so the remote knows who the caller is.
(message, hasCompose) = OFTMsgCodec.encode(
_sendParam.to,
_toSD(_amountLD),
// @dev Must be include a non empty bytes if you want to compose, EVEN if you dont need it on the remote.
// EVEN if you dont require an arbitrary payload to be sent... eg. '0x01'
_sendParam.composeMsg
);
// @dev Change the msg type depending if its composed or not.
uint16 msgType = hasCompose ? SEND_AND_CALL : SEND;
// @dev Combine the callers _extraOptions with the enforced options via the OAppOptionsType3.
options = combineOptions(_sendParam.dstEid, msgType, _sendParam.extraOptions);
OFTCoreStorage storage $ = _getOFTCoreStorage();
// @dev Optionally inspect the message and options depending if the OApp owner has set a msg inspector.
// @dev If it fails inspection, needs to revert in the implementation. ie. does not rely on return boolean
address inspector = $.msgInspector; // caches the msgInspector to avoid potential double storage read
if (inspector != address(0)) IOAppMsgInspector(inspector).inspect(message, options);
}
/**
* @dev Internal function to handle the receive on the LayerZero endpoint.
* @param _origin The origin information.
* - srcEid: The source chain endpoint ID.
* - sender: The sender address from the src chain.
* - nonce: The nonce of the LayerZero message.
* @param _guid The unique identifier for the received LayerZero message.
* @param _message The encoded message.
* @dev _executor The address of the executor.
* @dev _extraData Additional data.
*/
function _lzReceive(
Origin calldata _origin,
bytes32 _guid,
bytes calldata _message,
address /*_executor*/, // @dev unused in the default implementation.
bytes calldata /*_extraData*/ // @dev unused in the default implementation.
) internal virtual override {
// @dev The src sending chain doesnt know the address length on this chain (potentially non-evm)
// Thus everything is bytes32() encoded in flight.
address toAddress = _message.sendTo().bytes32ToAddress();
// @dev Credit the amountLD to the recipient and return the ACTUAL amount the recipient received in local decimals
uint256 amountReceivedLD = _credit(toAddress, _toLD(_message.amountSD()), _origin.srcEid);
if (_message.isComposed()) {
// @dev Proprietary composeMsg format for the OFT.
bytes memory composeMsg = OFTComposeMsgCodec.encode(
_origin.nonce,
_origin.srcEid,
amountReceivedLD,
_message.composeMsg()
);
// @dev Stores the lzCompose payload that will be executed in a separate tx.
// Standardizes functionality for executing arbitrary contract invocation on some non-evm chains.
// @dev The off-chain executor will listen and process the msg based on the src-chain-callers compose options passed.
// @dev The index is used when a OApp needs to compose multiple msgs on lzReceive.
// For default OFT implementation there is only 1 compose msg per lzReceive, thus its always 0.
endpoint.sendCompose(toAddress, _guid, 0 /* the index of the composed message*/, composeMsg);
}
emit OFTReceived(_guid, _origin.srcEid, toAddress, amountReceivedLD);
}
/**
* @dev Internal function to handle the OAppPreCrimeSimulator simulated receive.
* @param _origin The origin information.
* - srcEid: The source chain endpoint ID.
* - sender: The sender address from the src chain.
* - nonce: The nonce of the LayerZero message.
* @param _guid The unique identifier for the received LayerZero message.
* @param _message The LayerZero message.
* @param _executor The address of the off-chain executor.
* @param _extraData Arbitrary data passed by the msg executor.
*
* @dev Enables the preCrime simulator to mock sending lzReceive() messages,
* routes the msg down from the OAppPreCrimeSimulator, and back up to the OAppReceiver.
*/
function _lzReceiveSimulate(
Origin calldata _origin,
bytes32 _guid,
bytes calldata _message,
address _executor,
bytes calldata _extraData
) internal virtual override {
_lzReceive(_origin, _guid, _message, _executor, _extraData);
}
/**
* @dev Check if the peer is considered 'trusted' by the OApp.
* @param _eid The endpoint ID to check.
* @param _peer The peer to check.
* @return Whether the peer passed is considered 'trusted' by the OApp.
*
* @dev Enables OAppPreCrimeSimulator to check whether a potential Inbound Packet is from a trusted source.
*/
function isPeer(uint32 _eid, bytes32 _peer) public view virtual override returns (bool) {
return peers(_eid) == _peer;
}
/**
* @dev Internal function to remove dust from the given local decimal amount.
* @param _amountLD The amount in local decimals.
* @return amountLD The amount after removing dust.
*
* @dev Prevents the loss of dust when moving amounts between chains with different decimals.
* @dev eg. uint(123) with a conversion rate of 100 becomes uint(100).
*/
function _removeDust(uint256 _amountLD) internal view virtual returns (uint256 amountLD) {
return (_amountLD / decimalConversionRate) * decimalConversionRate;
}
/**
* @dev Internal function to convert an amount from shared decimals into local decimals.
* @param _amountSD The amount in shared decimals.
* @return amountLD The amount in local decimals.
*/
function _toLD(uint64 _amountSD) internal view virtual returns (uint256 amountLD) {
return _amountSD * decimalConversionRate;
}
/**
* @dev Internal function to convert an amount from local decimals into shared decimals.
* @param _amountLD The amount in local decimals.
* @return amountSD The amount in shared decimals.
*/
function _toSD(uint256 _amountLD) internal view virtual returns (uint64 amountSD) {
return uint64(_amountLD / decimalConversionRate);
}
/**
* @dev Internal function to mock the amount mutation from a OFT debit() operation.
* @param _amountLD The amount to send in local decimals.
* @param _minAmountLD The minimum amount to send in local decimals.
* @dev _dstEid The destination endpoint ID.
* @return amountSentLD The amount sent, in local decimals.
* @return amountReceivedLD The amount to be received on the remote chain, in local decimals.
*
* @dev This is where things like fees would be calculated and deducted from the amount to be received on the remote.
*/
function _debitView(
uint256 _amountLD,
uint256 _minAmountLD,
uint32 /*_dstEid*/
) internal view virtual returns (uint256 amountSentLD, uint256 amountReceivedLD) {
// @dev Remove the dust so nothing is lost on the conversion between chains with different decimals for the token.
amountSentLD = _removeDust(_amountLD);
// @dev The amount to send is the same as amount received in the default implementation.
amountReceivedLD = amountSentLD;
// @dev Check for slippage.
if (amountReceivedLD < _minAmountLD) {
revert SlippageExceeded(amountReceivedLD, _minAmountLD);
}
}
/**
* @dev Internal function to perform a debit operation.
* @param _from The address to debit from.
* @param _amountLD The amount to send in local decimals.
* @param _minAmountLD The minimum amount to send in local decimals.
* @param _dstEid The destination endpoint ID.
* @return amountSentLD The amount sent in local decimals.
* @return amountReceivedLD The amount received in local decimals on the remote.
*
* @dev Defined here but are intended to be overriden depending on the OFT implementation.
* @dev Depending on OFT implementation the _amountLD could differ from the amountReceivedLD.
*/
function _debit(
address _from,
uint256 _amountLD,
uint256 _minAmountLD,
uint32 _dstEid
) internal virtual returns (uint256 amountSentLD, uint256 amountReceivedLD);
/**
* @dev Internal function to perform a credit operation.
* @param _to The address to credit.
* @param _amountLD The amount to credit in local decimals.
* @param _srcEid The source endpoint ID.
* @return amountReceivedLD The amount ACTUALLY received in local decimals.
*
* @dev Defined here but are intended to be overriden depending on the OFT implementation.
* @dev Depending on OFT implementation the _amountLD could differ from the amountReceivedLD.
*/
function _credit(
address _to,
uint256 _amountLD,
uint32 _srcEid
) internal virtual returns (uint256 amountReceivedLD);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { MessagingReceipt, MessagingFee } from "@layerzerolabs/oapp-evm/contracts/oapp/OAppSender.sol";
/**
* @dev Struct representing token parameters for the OFT send() operation.
*/
struct SendParam {
uint32 dstEid; // Destination endpoint ID.
bytes32 to; // Recipient address.
uint256 amountLD; // Amount to send in local decimals.
uint256 minAmountLD; // Minimum amount to send in local decimals.
bytes extraOptions; // Additional options supplied by the caller to be used in the LayerZero message.
bytes composeMsg; // The composed message for the send() operation.
bytes oftCmd; // The OFT command to be executed, unused in default OFT implementations.
}
/**
* @dev Struct representing OFT limit information.
* @dev These amounts can change dynamically and are up the specific oft implementation.
*/
struct OFTLimit {
uint256 minAmountLD; // Minimum amount in local decimals that can be sent to the recipient.
uint256 maxAmountLD; // Maximum amount in local decimals that can be sent to the recipient.
}
/**
* @dev Struct representing OFT receipt information.
*/
struct OFTReceipt {
uint256 amountSentLD; // Amount of tokens ACTUALLY debited from the sender in local decimals.
// @dev In non-default implementations, the amountReceivedLD COULD differ from this value.
uint256 amountReceivedLD; // Amount of tokens to be received on the remote side.
}
/**
* @dev Struct representing OFT fee details.
* @dev Future proof mechanism to provide a standardized way to communicate fees to things like a UI.
*/
struct OFTFeeDetail {
int256 feeAmountLD; // Amount of the fee in local decimals.
string description; // Description of the fee.
}
/**
* @title IOFT
* @dev Interface for the OftChain (OFT) token.
* @dev Does not inherit ERC20 to accommodate usage by OFTAdapter as well.
* @dev This specific interface ID is '0x02e49c2c'.
*/
interface IOFT {
// Custom error messages
error InvalidLocalDecimals();
error SlippageExceeded(uint256 amountLD, uint256 minAmountLD);
// Events
event OFTSent(
bytes32 indexed guid, // GUID of the OFT message.
uint32 dstEid, // Destination Endpoint ID.
address indexed fromAddress, // Address of the sender on the src chain.
uint256 amountSentLD, // Amount of tokens sent in local decimals.
uint256 amountReceivedLD // Amount of tokens received in local decimals.
);
event OFTReceived(
bytes32 indexed guid, // GUID of the OFT message.
uint32 srcEid, // Source Endpoint ID.
address indexed toAddress, // Address of the recipient on the dst chain.
uint256 amountReceivedLD // Amount of tokens received in local decimals.
);
/**
* @notice Retrieves interfaceID and the version of the OFT.
* @return interfaceId The interface ID.
* @return version The version.
*
* @dev interfaceId: This specific interface ID is '0x02e49c2c'.
* @dev version: Indicates a cross-chain compatible msg encoding with other OFTs.
* @dev If a new feature is added to the OFT cross-chain msg encoding, the version will be incremented.
* ie. localOFT version(x,1) CAN send messages to remoteOFT version(x,1)
*/
function oftVersion() external view returns (bytes4 interfaceId, uint64 version);
/**
* @notice Retrieves the address of the token associated with the OFT.
* @return token The address of the ERC20 token implementation.
*/
function token() external view returns (address);
/**
* @notice Indicates whether the OFT contract requires approval of the 'token()' to send.
* @return requiresApproval Needs approval of the underlying token implementation.
*
* @dev Allows things like wallet implementers to determine integration requirements,
* without understanding the underlying token implementation.
*/
function approvalRequired() external view returns (bool);
/**
* @notice Retrieves the shared decimals of the OFT.
* @return sharedDecimals The shared decimals of the OFT.
*/
function sharedDecimals() external view returns (uint8);
/**
* @notice Provides the fee breakdown and settings data for an OFT. Unused in the default implementation.
* @param _sendParam The parameters for the send operation.
* @return limit The OFT limit information.
* @return oftFeeDetails The details of OFT fees.
* @return receipt The OFT receipt information.
*/
function quoteOFT(
SendParam calldata _sendParam
) external view returns (OFTLimit memory, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory);
/**
* @notice Provides a quote for the send() operation.
* @param _sendParam The parameters for the send() operation.
* @param _payInLzToken Flag indicating whether the caller is paying in the LZ token.
* @return fee The calculated LayerZero messaging fee from the send() operation.
*
* @dev MessagingFee: LayerZero msg fee
* - nativeFee: The native fee.
* - lzTokenFee: The lzToken fee.
*/
function quoteSend(SendParam calldata _sendParam, bool _payInLzToken) external view returns (MessagingFee memory);
/**
* @notice Executes the send() operation.
* @param _sendParam The parameters for the send operation.
* @param _fee The fee information supplied by the caller.
* - nativeFee: The native fee.
* - lzTokenFee: The lzToken fee.
* @param _refundAddress The address to receive any excess funds from fees etc. on the src.
* @return receipt The LayerZero messaging receipt from the send() operation.
* @return oftReceipt The OFT receipt information.
*
* @dev MessagingReceipt: LayerZero msg receipt
* - guid: The unique identifier for the sent message.
* - nonce: The nonce of the sent message.
* - fee: The LayerZero fee incurred for the message.
*/
function send(
SendParam calldata _sendParam,
MessagingFee calldata _fee,
address _refundAddress
) external payable returns (MessagingReceipt memory, OFTReceipt memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
library OFTComposeMsgCodec {
// Offset constants for decoding composed messages
uint8 private constant NONCE_OFFSET = 8;
uint8 private constant SRC_EID_OFFSET = 12;
uint8 private constant AMOUNT_LD_OFFSET = 44;
uint8 private constant COMPOSE_FROM_OFFSET = 76;
/**
* @dev Encodes a OFT composed message.
* @param _nonce The nonce value.
* @param _srcEid The source endpoint ID.
* @param _amountLD The amount in local decimals.
* @param _composeMsg The composed message.
* @return _msg The encoded Composed message.
*/
function encode(
uint64 _nonce,
uint32 _srcEid,
uint256 _amountLD,
bytes memory _composeMsg // 0x[composeFrom][composeMsg]
) internal pure returns (bytes memory _msg) {
_msg = abi.encodePacked(_nonce, _srcEid, _amountLD, _composeMsg);
}
/**
* @dev Retrieves the nonce for the composed message.
* @param _msg The message.
* @return The nonce value.
*/
function nonce(bytes calldata _msg) internal pure returns (uint64) {
return uint64(bytes8(_msg[:NONCE_OFFSET]));
}
/**
* @dev Retrieves the source endpoint ID for the composed message.
* @param _msg The message.
* @return The source endpoint ID.
*/
function srcEid(bytes calldata _msg) internal pure returns (uint32) {
return uint32(bytes4(_msg[NONCE_OFFSET:SRC_EID_OFFSET]));
}
/**
* @dev Retrieves the amount in local decimals from the composed message.
* @param _msg The message.
* @return The amount in local decimals.
*/
function amountLD(bytes calldata _msg) internal pure returns (uint256) {
return uint256(bytes32(_msg[SRC_EID_OFFSET:AMOUNT_LD_OFFSET]));
}
/**
* @dev Retrieves the composeFrom value from the composed message.
* @param _msg The message.
* @return The composeFrom value.
*/
function composeFrom(bytes calldata _msg) internal pure returns (bytes32) {
return bytes32(_msg[AMOUNT_LD_OFFSET:COMPOSE_FROM_OFFSET]);
}
/**
* @dev Retrieves the composed message.
* @param _msg The message.
* @return The composed message.
*/
function composeMsg(bytes calldata _msg) internal pure returns (bytes memory) {
return _msg[COMPOSE_FROM_OFFSET:];
}
/**
* @dev Converts an address to bytes32.
* @param _addr The address to convert.
* @return The bytes32 representation of the address.
*/
function addressToBytes32(address _addr) internal pure returns (bytes32) {
return bytes32(uint256(uint160(_addr)));
}
/**
* @dev Converts bytes32 to an address.
* @param _b The bytes32 value to convert.
* @return The address representation of bytes32.
*/
function bytes32ToAddress(bytes32 _b) internal pure returns (address) {
return address(uint160(uint256(_b)));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
library OFTMsgCodec {
// Offset constants for encoding and decoding OFT messages
uint8 private constant SEND_TO_OFFSET = 32;
uint8 private constant SEND_AMOUNT_SD_OFFSET = 40;
/**
* @dev Encodes an OFT LayerZero message.
* @param _sendTo The recipient address.
* @param _amountShared The amount in shared decimals.
* @param _composeMsg The composed message.
* @return _msg The encoded message.
* @return hasCompose A boolean indicating whether the message has a composed payload.
*/
function encode(
bytes32 _sendTo,
uint64 _amountShared,
bytes memory _composeMsg
) internal view returns (bytes memory _msg, bool hasCompose) {
hasCompose = _composeMsg.length > 0;
// @dev Remote chains will want to know the composed function caller ie. msg.sender on the src.
_msg = hasCompose
? abi.encodePacked(_sendTo, _amountShared, addressToBytes32(msg.sender), _composeMsg)
: abi.encodePacked(_sendTo, _amountShared);
}
/**
* @dev Checks if the OFT message is composed.
* @param _msg The OFT message.
* @return A boolean indicating whether the message is composed.
*/
function isComposed(bytes calldata _msg) internal pure returns (bool) {
return _msg.length > SEND_AMOUNT_SD_OFFSET;
}
/**
* @dev Retrieves the recipient address from the OFT message.
* @param _msg The OFT message.
* @return The recipient address.
*/
function sendTo(bytes calldata _msg) internal pure returns (bytes32) {
return bytes32(_msg[:SEND_TO_OFFSET]);
}
/**
* @dev Retrieves the amount in shared decimals from the OFT message.
* @param _msg The OFT message.
* @return The amount in shared decimals.
*/
function amountSD(bytes calldata _msg) internal pure returns (uint64) {
return uint64(bytes8(_msg[SEND_TO_OFFSET:SEND_AMOUNT_SD_OFFSET]));
}
/**
* @dev Retrieves the composed message from the OFT message.
* @param _msg The OFT message.
* @return The composed message.
*/
function composeMsg(bytes calldata _msg) internal pure returns (bytes memory) {
return _msg[SEND_AMOUNT_SD_OFFSET:];
}
/**
* @dev Converts an address to bytes32.
* @param _addr The address to convert.
* @return The bytes32 representation of the address.
*/
function addressToBytes32(address _addr) internal pure returns (bytes32) {
return bytes32(uint256(uint160(_addr)));
}
/**
* @dev Converts bytes32 to an address.
* @param _b The bytes32 value to convert.
* @return The address representation of bytes32.
*/
function bytes32ToAddress(bytes32 _b) internal pure returns (address) {
return address(uint160(uint256(_b)));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Ownable
struct OwnableStorage {
address _owner;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
assembly {
$.slot := OwnableStorageLocation
}
}
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
function __Ownable_init(address initialOwner) internal onlyInitializing {
__Ownable_init_unchained(initialOwner);
}
function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
OwnableStorage storage $ = _getOwnableStorage();
return $._owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
OwnableStorage storage $ = _getOwnableStorage();
address oldOwner = $._owner;
$._owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC-20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC-721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC-1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC-20
* applications.
*/
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Skips emitting an {Approval} event indicating an allowance update. This is not
* required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
*
* ```solidity
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance < type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC-20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* 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[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @title IERC7802
/// @notice Defines the interface for crosschain ERC20 transfers.
interface IERC7802 {
/// @notice Emitted when a crosschain transfer mints tokens.
/// @param to Address of the account tokens are being minted for.
/// @param amount Amount of tokens minted.
/// @param sender Address of the caller (msg.sender) who invoked crosschainMint.
event CrosschainMint(address indexed to, uint256 amount, address indexed sender);
/// @notice Emitted when a crosschain transfer burns tokens.
/// @param from Address of the account tokens are being burned from.
/// @param amount Amount of tokens burned.
/// @param sender Address of the caller (msg.sender) who invoked crosschainBurn.
event CrosschainBurn(address indexed from, uint256 amount, address indexed sender);
/// @notice Mint tokens through a crosschain transfer.
/// @param _to Address to mint tokens to.
/// @param _amount Amount of tokens to mint.
function crosschainMint(address _to, uint256 _amount) external;
/// @notice Burn tokens through a crosschain transfer.
/// @param _from Address to burn tokens from.
/// @param _amount Amount of tokens to burn.
function crosschainBurn(address _from, uint256 _amount) external;
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { IERC7802 } from "../interfaces/IERC7802.sol";
// @dev WARNING: This is for testing purposes only
contract ERC20Mock is ERC20, IERC7802 {
constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) {}
function crosschainMint(address _to, uint256 _amount) public {
_mint(_to, _amount);
emit CrosschainMint(_to, _amount, msg.sender);
}
function crosschainBurn(address _from, uint256 _amount) public {
_burn(_from, _amount);
emit CrosschainBurn(_from, _amount, msg.sender);
}
function decimals() public view override returns (uint8) {
return 6;
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { IERC7802 } from "../interfaces/IERC7802.sol";
// @dev WARNING: This is for testing purposes only
contract ERC20Mock18 is ERC20, IERC7802 {
constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) {}
function crosschainMint(address _to, uint256 _amount) public {
_mint(_to, _amount);
emit CrosschainMint(_to, _amount, msg.sender);
}
function crosschainBurn(address _from, uint256 _amount) public {
_burn(_from, _amount);
emit CrosschainBurn(_from, _amount, msg.sender);
}
function decimals() public view override returns (uint8) {
return 18;
}
}// Sources flattened with hardhat v2.22.16 https://hardhat.org // SPDX-License-Identifier: Apache AND MIT AND UNLICENSED // File @openzeppelin/contracts-upgradeable/proxy/utils/[email protected] // Original license: MIT pragma solidity ^0.8.0; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { require(_initializing || !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } } // File @openzeppelin/contracts-upgradeable/utils/[email protected] // Original license: MIT 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 ContextUpgradeable is Initializable { function __Context_init() internal initializer { __Context_init_unchained(); } function __Context_init_unchained() internal initializer { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } uint256[50] private __gap; } // File @openzeppelin/contracts-upgradeable/access/[email protected] // Original license: MIT pragma solidity ^0.8.0; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal initializer { __Context_init_unchained(); __Ownable_init_unchained(); } function __Ownable_init_unchained() internal initializer { _setOwner(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _setOwner(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"); _setOwner(newOwner); } function _setOwner(address newOwner) private { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } uint256[49] private __gap; } // File @openzeppelin/contracts-upgradeable/token/ERC20/[email protected] // Original license: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } // File @openzeppelin/contracts-upgradeable/token/ERC20/extensions/[email protected] // Original license: MIT pragma solidity ^0.8.0; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20MetadataUpgradeable is IERC20Upgradeable { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); } // File @openzeppelin/contracts-upgradeable/token/ERC20/[email protected] // Original license: MIT pragma solidity ^0.8.0; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name_, string memory symbol_) internal initializer { __Context_init_unchained(); __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal initializer { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom( address sender, address recipient, uint256 amount ) public virtual override returns (bool) { _transfer(sender, recipient, amount); uint256 currentAllowance = _allowances[sender][_msgSender()]; require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); unchecked { _approve(sender, _msgSender(), currentAllowance - amount); } return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { uint256 currentAllowance = _allowances[_msgSender()][spender]; require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(_msgSender(), spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `sender` to `recipient`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer( address sender, address recipient, uint256 amount ) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); uint256 senderBalance = _balances[sender]; require(senderBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[sender] = senderBalance - amount; } _balances[recipient] += amount; emit Transfer(sender, recipient, amount); _afterTokenTransfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; _balances[account] += amount; emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; } _totalSupply -= amount; emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} uint256[45] private __gap; } // File @openzeppelin/contracts-upgradeable/token/ERC20/extensions/[email protected] // Original license: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20PermitUpgradeable { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); } // File @openzeppelin/contracts-upgradeable/utils/[email protected] // Original license: MIT pragma solidity ^0.8.0; /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids. * * Include with `using Counters for Counters.Counter;` */ library CountersUpgradeable { struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { unchecked { counter._value += 1; } } function decrement(Counter storage counter) internal { uint256 value = counter._value; require(value > 0, "Counter: decrement overflow"); unchecked { counter._value = value - 1; } } function reset(Counter storage counter) internal { counter._value = 0; } } // File @openzeppelin/contracts-upgradeable/utils/cryptography/[email protected] // Original license: MIT pragma solidity ^0.8.0; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSAUpgradeable { /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { // Check the signature length // - case 65: r,s,v signature (standard) // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._ if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return recover(hash, v, r, s); } else if (signature.length == 64) { bytes32 r; bytes32 vs; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly { r := mload(add(signature, 0x20)) vs := mload(add(signature, 0x40)) } return recover(hash, r, vs); } else { revert("ECDSA: invalid signature length"); } } /** * @dev Overload of {ECDSA-recover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { bytes32 s; uint8 v; assembly { s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) v := add(shr(255, vs), 27) } return recover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. require( uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "ECDSA: invalid signature 's' value" ); require(v == 27 || v == 28, "ECDSA: invalid signature 'v' value"); // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); require(signer != address(0), "ECDSA: invalid signature"); return signer; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } } // File @openzeppelin/contracts-upgradeable/utils/cryptography/[email protected] // Original license: MIT pragma solidity ^0.8.0; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. * * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding * they need in their contracts using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * _Available since v3.4._ */ abstract contract EIP712Upgradeable is Initializable { /* solhint-disable var-name-mixedcase */ bytes32 private _HASHED_NAME; bytes32 private _HASHED_VERSION; bytes32 private constant _TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); /* solhint-enable var-name-mixedcase */ /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ function __EIP712_init(string memory name, string memory version) internal initializer { __EIP712_init_unchained(name, version); } function __EIP712_init_unchained(string memory name, string memory version) internal initializer { bytes32 hashedName = keccak256(bytes(name)); bytes32 hashedVersion = keccak256(bytes(version)); _HASHED_NAME = hashedName; _HASHED_VERSION = hashedVersion; } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { return _buildDomainSeparator(_TYPE_HASH, _EIP712NameHash(), _EIP712VersionHash()); } function _buildDomainSeparator( bytes32 typeHash, bytes32 nameHash, bytes32 versionHash ) private view returns (bytes32) { return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return ECDSAUpgradeable.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev The hash of the name parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712NameHash() internal virtual view returns (bytes32) { return _HASHED_NAME; } /** * @dev The hash of the version parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712VersionHash() internal virtual view returns (bytes32) { return _HASHED_VERSION; } uint256[50] private __gap; } // File @openzeppelin/contracts-upgradeable/token/ERC20/extensions/[email protected] // Original license: MIT pragma solidity ^0.8.0; /** * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * _Available since v3.4._ */ abstract contract ERC20PermitUpgradeable is Initializable, ERC20Upgradeable, IERC20PermitUpgradeable, EIP712Upgradeable { using CountersUpgradeable for CountersUpgradeable.Counter; mapping(address => CountersUpgradeable.Counter) private _nonces; // solhint-disable-next-line var-name-mixedcase bytes32 private _PERMIT_TYPEHASH; /** * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. * * It's a good idea to use the same `name` that is defined as the ERC20 token name. */ function __ERC20Permit_init(string memory name) internal initializer { __Context_init_unchained(); __EIP712_init_unchained(name, "1"); __ERC20Permit_init_unchained(name); } function __ERC20Permit_init_unchained(string memory name) internal initializer { _PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");} /** * @dev See {IERC20Permit-permit}. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual override { require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline)); bytes32 hash = _hashTypedDataV4(structHash); address signer = ECDSAUpgradeable.recover(hash, v, r, s); require(signer == owner, "ERC20Permit: invalid signature"); _approve(owner, spender, value); } /** * @dev See {IERC20Permit-nonces}. */ function nonces(address owner) public view virtual override returns (uint256) { return _nonces[owner].current(); } /** * @dev See {IERC20Permit-DOMAIN_SEPARATOR}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view override returns (bytes32) { return _domainSeparatorV4(); } /** * @dev "Consume a nonce": return the current value and increment. * * _Available since v4.1._ */ function _useNonce(address owner) internal virtual returns (uint256 current) { CountersUpgradeable.Counter storage nonce = _nonces[owner]; current = nonce.current(); nonce.increment(); } uint256[49] private __gap; } // File contracts/Tether/util/MessageHashUtils.sol /** * License: Apache-2.0 * * Copyright (c) 2023, Circle Internet Financial, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * --------------------------------------------------------------------- * * Adapted by Tether.to 2024 for greater flexibility and reusability */ pragma solidity >=0.6.12 <0.9.0; /** * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing. * * The library provides methods for generating a hash of a message that conforms to the * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712] * specifications. */ library MessageHashUtils { /** * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`). * Adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/21bb89ef5bfc789b9333eb05e3ba2b7b284ac77c/contracts/utils/cryptography/MessageHashUtils.sol * * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with * `\x19\x01` and hashing the result. It corresponds to the hash signed by the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712. * * @param domainSeparator Domain separator * @param structHash Hashed EIP-712 data struct * @return digest The keccak256 digest of an EIP-712 typed data */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, "\x19\x01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) digest := keccak256(ptr, 0x42) } } } // File contracts/Tether/interfaces/IERC1271.sol /** * License: Apache-2.0 * * Copyright (c) 2023, Circle Internet Financial, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * --------------------------------------------------------------------- * * Adapted by Tether.to 2024 for greater flexibility and reusability */ pragma solidity >=0.6.12 <0.9.0; /** * @dev Interface of the ERC1271 standard signature validation method for * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. */ interface IERC1271 { /** * @dev Should return whether the signature provided is valid for the provided data * @param hash Hash of the data to be signed * @param signature Signature byte array associated with the provided data hash * @return magicValue bytes4 magic value 0x1626ba7e when function passes */ function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); } // File contracts/Tether/util/ECRecover.sol /** * License: Apache-2.0 * * Copyright (c) 2023, Circle Internet Financial, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * --------------------------------------------------------------------- * * Adapted by Tether.to 2024 for greater flexibility and reusability */ pragma solidity >=0.6.12 <0.9.0; /** * @title ECRecover * @notice A library that provides a safe ECDSA recovery function */ library ECRecover { /** * @notice Recover signer's address from a signed message * @dev Adapted from: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/65e4ffde586ec89af3b7e9140bdc9235d1254853/contracts/cryptography/ECDSA.sol * Modifications: Accept v, r, and s as separate arguments * @param digest Keccak-256 hash digest of the signed message * @param v v of the signature * @param r r of the signature * @param s s of the signature * @return Signer address */ function recover( bytes32 digest, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if ( uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 ) { revert("ECRecover: invalid signature 's' value"); } if (v != 27 && v != 28) { revert("ECRecover: invalid signature 'v' value"); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(digest, v, r, s); require(signer != address(0), "ECRecover: invalid signature"); return signer; } /** * @notice Recover signer's address from a signed message * @dev Adapted from: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/0053ee040a7ff1dbc39691c9e67a69f564930a88/contracts/utils/cryptography/ECDSA.sol * @param digest Keccak-256 hash digest of the signed message * @param signature Signature byte array associated with hash * @return Signer address */ function recover(bytes32 digest, bytes memory signature) internal pure returns (address) { require(signature.length == 65, "ECRecover: invalid signature length"); bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return recover(digest, v, r, s); } } // File contracts/Tether/util/SignatureChecker.sol /** * License: Apache-2.0 * * Copyright (c) 2023, Circle Internet Financial, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * --------------------------------------------------------------------- * * Adapted by Tether.to 2024 for greater flexibility and reusability */ pragma solidity >=0.6.12 <0.9.0; /** * @dev Signature verification helper that can be used instead of `ECRecover.recover` to seamlessly support both ECDSA * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets. * * Adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/21bb89ef5bfc789b9333eb05e3ba2b7b284ac77c/contracts/utils/cryptography/SignatureChecker.sol */ library SignatureChecker { /** * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECRecover.recover`. * @param signer Address of the claimed signer * @param digest Keccak-256 hash digest of the signed message * @param signature signature byte array associated with hash */ function isValidSignatureNow( address signer, bytes32 digest, bytes memory signature ) internal view returns (bool) { if (!isContract(signer)) { return ECRecover.recover(digest, signature) == signer; } return isValidERC1271SignatureNow(signer, digest, signature); } /** * @dev Checks if a signature is valid for a given signer and data hash. The signature is validated * against the signer smart contract using ERC1271. * @param signer Address of the claimed signer * @param digest Keccak-256 hash digest of the signed message * @param signature Signature byte array associated with hash * * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus * change through time. It could return true at block N and false at block N+1 (or the opposite). */ function isValidERC1271SignatureNow( address signer, bytes32 digest, bytes memory signature ) internal view returns (bool) { (bool success, bytes memory result) = signer.staticcall( abi.encodeWithSelector( IERC1271.isValidSignature.selector, digest, signature ) ); return (success && result.length >= 32 && abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector)); } /** * @dev Checks if the input address is a smart contract. */ function isContract(address addr) internal view returns (bool) { uint256 size; assembly { size := extcodesize(addr) } return size > 0; } } // File contracts/Tether/EIP3009.sol /** * License: Apache-2.0 * * Copyright (c) 2023, Circle Internet Financial, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * --------------------------------------------------------------------- * * Adapted by Tether.to 2024 for greater flexibility and reusability */ pragma solidity >=0.6.12 <0.9.0; /** * @title EIP-3009 * @notice Provide internal implementation for gas-abstracted transfers * @dev Contracts that inherit from this must wrap these with publicly * accessible functions, optionally adding modifiers where necessary */ abstract contract EIP3009 { bytes32 public constant TRANSFER_WITH_AUTHORIZATION_TYPEHASH = keccak256("TransferWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)"); bytes32 public constant RECEIVE_WITH_AUTHORIZATION_TYPEHASH = keccak256("ReceiveWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)"); bytes32 public constant CANCEL_AUTHORIZATION_TYPEHASH = keccak256("CancelAuthorization(address authorizer,bytes32 nonce)"); /** * @dev authorizer address => nonce => bool (true if nonce is used) */ mapping(address => mapping(bytes32 => bool)) private _authorizationStates; event AuthorizationUsed(address indexed authorizer, bytes32 indexed nonce); event AuthorizationCanceled( address indexed authorizer, bytes32 indexed nonce ); function domainSeparator() internal virtual view returns (bytes32); /** * @notice Returns the state of an authorization * @dev Nonces are randomly generated 32-byte data unique to the * authorizer's address * @param authorizer Authorizer's address * @param nonce Nonce of the authorization * @return True if the nonce is used */ function authorizationState(address authorizer, bytes32 nonce) external view returns (bool) { return _authorizationStates[authorizer][nonce]; } /** * @notice Execute a transfer with a signed authorization * @param from Payer's address (Authorizer) * @param to Payee's address * @param value Amount to be transferred * @param validAfter The time after which this is valid (unix time) * @param validBefore The time before which this is valid (unix time) * @param nonce Unique nonce * @param signature signature in bytes */ function _transferWithAuthorizationValidityCheck( address from, address to, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 nonce, bytes memory signature ) internal { _requireValidAuthorization(from, nonce, validAfter, validBefore); _requireValidSignature( from, keccak256( abi.encode( TRANSFER_WITH_AUTHORIZATION_TYPEHASH, from, to, value, validAfter, validBefore, nonce ) ), signature ); _markAuthorizationAsUsed(from, nonce); } /** * @notice Receive a transfer with a signed authorization from the payer * @dev This has an additional check to ensure that the payee's address * matches the caller of this function to prevent front-running attacks. * @param from Payer's address (Authorizer) * @param to Payee's address * @param value Amount to be transferred * @param validAfter The time after which this is valid (unix time) * @param validBefore The time before which this is valid (unix time) * @param nonce Unique nonce * @param signature signature in bytes */ function _receiveWithAuthorizationValidityCheck( address from, address to, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 nonce, bytes memory signature ) internal { require(to == msg.sender, "TetherToken: to != msg.sender"); _requireValidAuthorization(from, nonce, validAfter, validBefore); _requireValidSignature( from, keccak256( abi.encode( RECEIVE_WITH_AUTHORIZATION_TYPEHASH, from, to, value, validAfter, validBefore, nonce ) ), signature ); _markAuthorizationAsUsed(from, nonce); } function _cancelAuthorization( address authorizer, bytes32 nonce, bytes memory signature ) internal { _requireUnusedAuthorization(authorizer, nonce); _requireValidSignature( authorizer, keccak256( abi.encode(CANCEL_AUTHORIZATION_TYPEHASH, authorizer, nonce) ), signature ); _authorizationStates[authorizer][nonce] = true; emit AuthorizationCanceled(authorizer, nonce); } /** * @notice Attempt to cancel an authorization * @param authorizer Authorizer's address * @param nonce Nonce of the authorization * @param v v of the signature * @param r r of the signature * @param s s of the signature */ function cancelAuthorization( address authorizer, bytes32 nonce, uint8 v, bytes32 r, bytes32 s ) public { _cancelAuthorization(authorizer, nonce, abi.encodePacked(r,s,v)); } /** * @notice Attempt to cancel an authorization * @dev Works only if the authorization is not yet used. * EOA wallet signatures should be packed in the order of r, s, v. * @param authorizer Authorizer's address * @param nonce Nonce of the authorization * @param signature Signature bytes signed by an EOA wallet or a contract wallet */ function cancelAuthorization( address authorizer, bytes32 nonce, bytes memory signature ) external { _cancelAuthorization(authorizer, nonce, signature); } /** * @notice Validates that signature against input data struct * @param signer Signer's address * @param dataHash Hash of encoded data struct * @param signature signature in bytes */ function _requireValidSignature( address signer, bytes32 dataHash, bytes memory signature ) private view { require( SignatureChecker.isValidSignatureNow( signer, MessageHashUtils.toTypedDataHash(domainSeparator(), dataHash), signature ), "TetherToken: invalid signature" ); } /** * @notice Check that an authorization is unused * @param authorizer Authorizer's address * @param nonce Nonce of the authorization */ function _requireUnusedAuthorization(address authorizer, bytes32 nonce) private view { require( !_authorizationStates[authorizer][nonce], "TetherToken: auth invalid" ); } /** * @notice Check that authorization is valid * @param authorizer Authorizer's address * @param nonce Nonce of the authorization * @param validAfter The time after which this is valid (unix time) * @param validBefore The time before which this is valid (unix time) */ function _requireValidAuthorization( address authorizer, bytes32 nonce, uint256 validAfter, uint256 validBefore ) private view { require( block.timestamp > validAfter, "TetherToken: auth early" ); require(block.timestamp < validBefore, "TetherToken: auth expired"); _requireUnusedAuthorization(authorizer, nonce); } /** * @notice Mark an authorization as used * @param authorizer Authorizer's address * @param nonce Nonce of the authorization */ function _markAuthorizationAsUsed(address authorizer, bytes32 nonce) private { _authorizationStates[authorizer][nonce] = true; emit AuthorizationUsed(authorizer, nonce); } uint256[49] private __gap; } // File contracts/Tether/WithBlockedList.sol // Original license: Apache /* Copyright Tether.to 2020 Author Will Harborne Licensed under the Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0 */ contract WithBlockedList is OwnableUpgradeable { /** * @dev Reverts if called by a blocked account */ modifier onlyNotBlocked() { require(!isBlocked[_msgSender()], "Blocked: msg.sender is blocked"); _; } mapping (address => bool) public isBlocked; function addToBlockedList (address _user) public onlyOwner { isBlocked[_user] = true; emit BlockPlaced(_user); } function removeFromBlockedList (address _user) public onlyOwner { isBlocked[_user] = false; emit BlockReleased(_user); } event BlockPlaced(address indexed _user); event BlockReleased(address indexed _user); } // File contracts/Tether/TetherToken.sol // Original license: Apache /* Copyright Tether.to 2024 Version 2.0(a) Licensed under the Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0 */ contract TetherToken is Initializable, ERC20PermitUpgradeable, OwnableUpgradeable, WithBlockedList { // Unused variable retained to preserve storage slots across upgrades mapping(address => bool) public isTrusted; uint8 private tetherDecimals; function initialize( string memory _name, string memory _symbol, uint8 _decimals ) public initializer { tetherDecimals = _decimals; __Ownable_init(); __ERC20_init(_name, _symbol); __ERC20Permit_init(_name); } function decimals() public view virtual override returns (uint8) { return tetherDecimals; } function _beforeTokenTransfer( address from, address to, uint256 ) internal virtual override { require(!isBlocked[from] || msg.sender == owner(), "TetherToken: from is blocked"); require( to != address(this), "TetherToken: transfer to the contract address" ); } function transferFrom( address _sender, address _recipient, uint256 _amount ) public virtual override onlyNotBlocked returns (bool) { return super.transferFrom(_sender, _recipient, _amount); } function multiTransfer ( address[] calldata _recipients, uint256[] calldata _values ) external { require( _recipients.length == _values.length, "TetherToken: multiTransfer mismatch" ); for (uint256 i = 0; i < _recipients.length; i++) { transfer(_recipients[i], _values[i]); } } function mint(address _destination, uint256 _amount) public virtual onlyOwner { _mint(_destination, _amount); emit Mint(_destination, _amount); } function redeem(uint256 _amount) public virtual onlyOwner { _burn(owner(), _amount); emit Redeem(_amount); } function destroyBlockedFunds(address _blockedUser) public onlyOwner { require(isBlocked[_blockedUser], "TetherToken: user is not blocked"); uint256 blockedFunds = balanceOf(_blockedUser); _burn(_blockedUser, blockedFunds); emit DestroyedBlockedFunds(_blockedUser, blockedFunds); } event Mint(address indexed _destination, uint256 _amount); event Redeem(uint256 _amount); event DestroyedBlockedFunds(address indexed _blockedUser, uint256 _balance); } // File contracts/Tether/TetherTokenV2.sol // Original license: Apache contract TetherTokenV2 is TetherToken, EIP3009 { bytes32 internal constant _PERMIT_TYPEHASH = keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ); constructor () {} function domainSeparator() internal view virtual override returns (bytes32) { return _domainSeparatorV4(); } /** * The following applies to the following function and comments to that function: * * License: Apache-2.0 * * Copyright (c) 2023, Circle Internet Financial, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * --------------------------------------------------------------------- * * Adapted by Tether.to 2024 for greater flexibility and reusability */ function _permit( address owner_, address spender, uint256 value, uint256 deadline, bytes memory signature ) internal { require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); bytes32 structHash = keccak256( abi.encode( _PERMIT_TYPEHASH, owner_, spender, value, _useNonce(owner_), deadline ) ); bytes32 hash = _hashTypedDataV4(structHash); require( SignatureChecker.isValidSignatureNow(owner_, hash, signature), "EIP2612: invalid signature" ); _approve(owner_, spender, value); } /** * @notice Update allowance with a signed permit * @param owner_ Token owner's address * @param spender Spender's address * @param value Amount of allowance * @param deadline The time at which the signature expires (unix time) * @param v signature component v * @param r signature component r * @param s signature component s */ function permit( address owner_, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public virtual override { _permit(owner_, spender, value, deadline, abi.encodePacked(r, s, v)); } /** * The following applies to the following function and comments to that function: * * License: Apache-2.0 * * Copyright (c) 2023, Circle Internet Financial, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * --------------------------------------------------------------------- * * Adapted by Tether.to 2024 for greater flexibility and reusability */ /** * @notice Update allowance with a signed permit * @dev EOA wallet signatures should be packed in the order of r, s, v. * @param owner_ Token owner's address (Authorizer) * @param spender Spender's address * @param value Amount of allowance * @param deadline The time at which the signature expires (unix time), or max uint256 value to signal no expiration * @param signature Signature bytes signed by an EOA wallet or a contract wallet */ function permit( address owner_, address spender, uint256 value, uint256 deadline, bytes memory signature ) external { _permit(owner_, spender, value, deadline, signature); } /** * The following applies to the following function and comments to that function: * * License: Apache-2.0 * * Copyright (c) 2023, Circle Internet Financial, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * --------------------------------------------------------------------- * * Adapted by Tether.to 2024 for greater flexibility and reusability */ /** * @notice Execute a transfer with a signed authorization * @param from Payer's address (Authorizer) * @param to Payee's address * @param value Amount to be transferred * @param validAfter The time after which this is valid (unix time) * @param validBefore The time before which this is valid (unix time) * @param nonce Unique nonce * @param v v of the signature * @param r r of the signature * @param s s of the signature */ function transferWithAuthorization( address from, address to, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 nonce, uint8 v, bytes32 r, bytes32 s ) public onlyNotBlocked { _transferWithAuthorizationValidityCheck( from, to, value, validAfter, validBefore, nonce, abi.encodePacked(r, s, v) ); _transfer(from, to, value); } /** * The following applies to the following function and comments to that function: * * License: Apache-2.0 * * Copyright (c) 2023, Circle Internet Financial, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * --------------------------------------------------------------------- * * Adapted by Tether.to 2024 for greater flexibility and reusability */ /** * @notice Execute a transfer with a signed authorization * @dev EOA wallet signatures should be packed in the order of r, s, v. * @param from Payer's address (Authorizer) * @param to Payee's address * @param value Amount to be transferred * @param validAfter The time after which this is valid (unix time) * @param validBefore The time before which this is valid (unix time) * @param nonce Unique nonce * @param signature Signature bytes signed by an EOA wallet or a contract wallet */ function transferWithAuthorization( address from, address to, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 nonce, bytes memory signature ) external onlyNotBlocked { _transferWithAuthorizationValidityCheck( from, to, value, validAfter, validBefore, nonce, signature ); _transfer(from, to, value); } /** * The following applies to the following function and comments to that function: * * License: Apache-2.0 * * Copyright (c) 2023, Circle Internet Financial, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * --------------------------------------------------------------------- * * Adapted by Tether.to 2024 for greater flexibility and reusability */ /** * @notice Receive a transfer with a signed authorization from the payer * @dev This has an additional check to ensure that the payee's address * matches the caller of this function to prevent front-running attacks. * @param from Payer's address (Authorizer) * @param to Payee's address * @param value Amount to be transferred * @param validAfter The time after which this is valid (unix time) * @param validBefore The time before which this is valid (unix time) * @param nonce Unique nonce * @param v v of the signature * @param r r of the signature * @param s s of the signature */ function receiveWithAuthorization( address from, address to, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 nonce, uint8 v, bytes32 r, bytes32 s ) public onlyNotBlocked { _receiveWithAuthorizationValidityCheck( from, to, value, validAfter, validBefore, nonce, abi.encodePacked(r, s, v) ); _transfer(from, to, value); } /** * The following applies to the following function and comments to that function: * * License: Apache-2.0 * * Copyright (c) 2023, Circle Internet Financial, LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * --------------------------------------------------------------------- * * Adapted by Tether.to 2024 for greater flexibility and reusability */ /** * @notice Receive a transfer with a signed authorization from the payer * @dev This has an additional check to ensure that the payee's address * matches the caller of this function to prevent front-running attacks. * EOA wallet signatures should be packed in the order of r, s, v. * @param from Payer's address (Authorizer) * @param to Payee's address * @param value Amount to be transferred * @param validAfter The time after which this is valid (unix time) * @param validBefore The time before which this is valid (unix time) * @param nonce Unique nonce * @param signature Signature bytes signed by an EOA wallet or a contract wallet */ function receiveWithAuthorization( address from, address to, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 nonce, bytes memory signature ) external onlyNotBlocked { _receiveWithAuthorizationValidityCheck( from, to, value, validAfter, validBefore, nonce, signature ); _transfer(from, to, value); } uint256[48] private __gap; } // File contracts/Wrappers/OFTExtension.sol // Original license: Apache /* Copyright Tether.to 2024 Author Will Norden Licensed under the Apache License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0 */ contract TetherTokenOFTExtension is TetherTokenV2 { event LogSetOFTContract(address indexed oftContract); event Burn(address indexed from, uint256 amount); event LogUpdateNameAndSymbol(string name, string symbol); address public oftContract; string internal _newName; // Unused variable for compatibility string internal _newSymbol; // Unused variable for compatibility modifier onlyAuthorizedSender() { require(msg.sender == oftContract, "Only OFT can call"); _; } function mint(address _destination, uint256 _amount) public override onlyAuthorizedSender { _mint(_destination, _amount); emit Mint(_destination, _amount); } function burn(address _from, uint256 _amount) public onlyAuthorizedSender { _burn(_from, _amount); emit Burn(_from, _amount); } function setOFTContract(address _oftContract) external onlyOwner { oftContract = _oftContract; emit LogSetOFTContract(_oftContract); } /** * @dev The hash of the name parameter for the EIP712 domain. * * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs * are a concern. */ function _EIP712NameHash() internal virtual override view returns (bytes32) { return keccak256(bytes(name())); } function updateNameAndSymbol(string memory _name, string memory _symbol) public onlyOwner { _newName = _name; _newSymbol = _symbol; emit LogUpdateNameAndSymbol(_name, _symbol); } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return bytes(_newName).length == 0 ? super.name() : _newName; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return bytes(_newSymbol).length == 0 ? super.symbol() : _newSymbol; } uint256[47] private __gap; } // File contracts/Wrappers/HyperliquidExtension.sol // Original license: UNLICENSED contract HyperliquidExtension is TetherTokenOFTExtension { event SetTrusted(address indexed _address, bool _isTrusted); function setTrusted(address _address, bool _isTrusted) external onlyOwner { isTrusted[_address] = _isTrusted; emit SetTrusted(_address, _isTrusted); } modifier onlyTrusted() { require(isTrusted[msg.sender], "Only trusted can call"); _; } function transferWithHop(address intermediate, address recipient, uint256 amount) external onlyTrusted { _transfer(msg.sender, intermediate, amount); _transfer(intermediate, recipient, amount); } }
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.22;
import { OUpgradeable, IOFTToken } from "../OUpgradeable.sol";
import { SendParam } from "@layerzerolabs/oft-evm-upgradeable/contracts/oft/OFTCoreUpgradeable.sol";
// @dev WARNING: This is for testing purposes only
contract OUpgradeableMock is OUpgradeable {
// address _lzEndpoint, IOFTToken _token, uint8 decimals
constructor(
address _lzEndpoint,
IOFTToken _token
) OUpgradeable(_lzEndpoint, _token) {}
function mint(address _to, uint256 _amount) public {
token_.crosschainMint(_to, _amount);
}
// @dev expose internal functions for testing purposes
function debit(
uint256 _amountToSendLD,
uint256 _minAmountToCreditLD,
uint32 _dstEid
) public returns (uint256 amountDebitedLD, uint256 amountToCreditLD) {
return _debit(msg.sender, _amountToSendLD, _minAmountToCreditLD, _dstEid);
}
function debitView(
uint256 _amountToSendLD,
uint256 _minAmountToCreditLD,
uint32 _dstEid
) public view returns (uint256 amountDebitedLD, uint256 amountToCreditLD) {
return _debitView(_amountToSendLD, _minAmountToCreditLD, _dstEid);
}
function removeDust(uint256 _amountLD) public view returns (uint256 amountLD) {
return _removeDust(_amountLD);
}
function toLD(uint64 _amountSD) public view returns (uint256 amountLD) {
return _toLD(_amountSD);
}
function toSD(uint256 _amountLD) public view returns (uint64 amountSD) {
return _toSD(_amountLD);
}
function credit(address _to, uint256 _amountToCreditLD, uint32 _srcEid) public returns (uint256 amountReceivedLD) {
return _credit(_to, _amountToCreditLD, _srcEid);
}
function buildMsgAndOptions(
SendParam calldata _sendParam,
uint256 _amountToCreditLD
) public view returns (bytes memory message, bytes memory options) {
return _buildMsgAndOptions(_sendParam, _amountToCreditLD);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IOAppComposer } from "@layerzerolabs/oapp-evm/contracts/oapp/interfaces/IOAppComposer.sol";
import { OFTComposeMsgCodec } from "@layerzerolabs/oft-evm/contracts/libs/OFTComposeMsgCodec.sol";
import { IOFT } from "@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol";
interface IHyperliquidExtension is IERC20 {
event SetTrusted(address indexed _address, bool _isTrusted);
function setTrusted(address _address, bool _isTrusted) external;
function transferWithHop(address intermediate, address recipient, uint256 amount) external;
function oftContract() external view returns (address);
}
/// @title HyperLiquidComposer Contract
/// @notice The contract is intended to transfer tokens to the HL L1
contract HyperLiquidComposer is IOAppComposer {
event Unwrap(address indexed user, address tokenOut, uint256 amount);
IHyperliquidExtension public immutable token;
address constant public HL_NATIVE_TRANSFER = 0x2222222222222222222222222222222222222222;
address public immutable endpoint;
address public immutable oApp;
/// @notice Constructs the HyperLiquidComposer contract.
/// @dev Initializes the contract.
/// @param _endpoint LayerZero Endpoint address
/// @param _oApp The address of the OApp that is sending the composed message.
constructor(address _endpoint, address _oApp) {
require(_endpoint != address(0), "Zero address");
require(_oApp != address(0), "Zero address");
token = IHyperliquidExtension(IOFT(_oApp).token());
endpoint = _endpoint;
oApp = _oApp;
}
/// @notice Handles incoming composed messages from LayerZero.
/// @dev This method expects the encoded compose message to contain the recipient address.
/// @param _oApp The address of the originating OApp.
/// @param /*_guid*/ The globally unique identifier of the message.
/// @param _message The encoded message content in the format of the OFTComposeMsgCodec.
/// @param /*Executor*/ Executor address.
/// @param /*Executor Data*/ Additional data for checking for a specific executor.
function lzCompose(
address _oApp,
bytes32 /*_guid*/,
bytes calldata _message,
address /*Executor*/,
bytes calldata /*Executor Data*/
) external payable override {
require(_oApp == oApp, "!oApp");
require(msg.sender == endpoint, "!endpoint");
// Extract the composed message from the delivered message using the MsgCodec
address _receiver = abi.decode(OFTComposeMsgCodec.composeMsg(_message), (address));
uint256 _amountLD = OFTComposeMsgCodec.amountLD(_message);
// Execute the token swap by transferring the specified amount to the receiver
token.transferWithHop(_receiver, HL_NATIVE_TRANSFER, _amountLD);
// Emit an event to log the token swap details
emit Unwrap(_receiver, address(token), _amountLD);
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_lzEndpoint","type":"address"},{"internalType":"contract IOFTToken","name":"_token","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidDelegate","type":"error"},{"inputs":[],"name":"InvalidEndpointCall","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidLocalDecimals","type":"error"},{"inputs":[{"internalType":"bytes","name":"options","type":"bytes"}],"name":"InvalidOptions","type":"error"},{"inputs":[],"name":"LzTokenUnavailable","type":"error"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"}],"name":"NoPeer","type":"error"},{"inputs":[{"internalType":"uint256","name":"msgValue","type":"uint256"}],"name":"NotEnoughNative","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"OnlyEndpoint","type":"error"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"}],"name":"OnlyPeer","type":"error"},{"inputs":[],"name":"OnlySelf","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"bytes","name":"result","type":"bytes"}],"name":"SimulationResult","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"}],"name":"SlippageExceeded","type":"error"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"uint16","name":"msgType","type":"uint16"},{"internalType":"bytes","name":"options","type":"bytes"}],"indexed":false,"internalType":"struct EnforcedOptionParam[]","name":"_enforcedOptions","type":"tuple[]"}],"name":"EnforcedOptionSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"inspector","type":"address"}],"name":"MsgInspectorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"guid","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"srcEid","type":"uint32"},{"indexed":true,"internalType":"address","name":"toAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountReceivedLD","type":"uint256"}],"name":"OFTReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"guid","type":"bytes32"},{"indexed":false,"internalType":"uint32","name":"dstEid","type":"uint32"},{"indexed":true,"internalType":"address","name":"fromAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountSentLD","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountReceivedLD","type":"uint256"}],"name":"OFTSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"eid","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"peer","type":"bytes32"}],"name":"PeerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"preCrimeAddress","type":"address"}],"name":"PreCrimeSet","type":"event"},{"inputs":[],"name":"SEND","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SEND_AND_CALL","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"origin","type":"tuple"}],"name":"allowInitializePath","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"approvalRequired","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint32","name":"_eid","type":"uint32"},{"internalType":"uint16","name":"_msgType","type":"uint16"},{"internalType":"bytes","name":"_extraOptions","type":"bytes"}],"name":"combineOptions","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimalConversionRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endpoint","outputs":[{"internalType":"contract ILayerZeroEndpointV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_eid","type":"uint32"},{"internalType":"uint16","name":"_msgType","type":"uint16"}],"name":"enforcedOptions","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_delegate","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"","type":"tuple"},{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"address","name":"_sender","type":"address"}],"name":"isComposeMsgSender","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_eid","type":"uint32"},{"internalType":"bytes32","name":"_peer","type":"bytes32"}],"name":"isPeer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"_origin","type":"tuple"},{"internalType":"bytes32","name":"_guid","type":"bytes32"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"lzReceive","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"origin","type":"tuple"},{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bytes32","name":"guid","type":"bytes32"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"address","name":"executor","type":"address"},{"internalType":"bytes","name":"message","type":"bytes"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct InboundPacket[]","name":"_packets","type":"tuple[]"}],"name":"lzReceiveAndRevert","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Origin","name":"_origin","type":"tuple"},{"internalType":"bytes32","name":"_guid","type":"bytes32"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"lzReceiveSimulate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"msgInspector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"nextNonce","outputs":[{"internalType":"uint64","name":"nonce","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oApp","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oAppVersion","outputs":[{"internalType":"uint64","name":"senderVersion","type":"uint64"},{"internalType":"uint64","name":"receiverVersion","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"oftVersion","outputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"},{"internalType":"uint64","name":"version","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"_eid","type":"uint32"}],"name":"peers","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"preCrime","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"},{"internalType":"bytes","name":"extraOptions","type":"bytes"},{"internalType":"bytes","name":"composeMsg","type":"bytes"},{"internalType":"bytes","name":"oftCmd","type":"bytes"}],"internalType":"struct SendParam","name":"_sendParam","type":"tuple"}],"name":"quoteOFT","outputs":[{"components":[{"internalType":"uint256","name":"minAmountLD","type":"uint256"},{"internalType":"uint256","name":"maxAmountLD","type":"uint256"}],"internalType":"struct OFTLimit","name":"oftLimit","type":"tuple"},{"components":[{"internalType":"int256","name":"feeAmountLD","type":"int256"},{"internalType":"string","name":"description","type":"string"}],"internalType":"struct OFTFeeDetail[]","name":"oftFeeDetails","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"amountSentLD","type":"uint256"},{"internalType":"uint256","name":"amountReceivedLD","type":"uint256"}],"internalType":"struct OFTReceipt","name":"oftReceipt","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"},{"internalType":"bytes","name":"extraOptions","type":"bytes"},{"internalType":"bytes","name":"composeMsg","type":"bytes"},{"internalType":"bytes","name":"oftCmd","type":"bytes"}],"internalType":"struct SendParam","name":"_sendParam","type":"tuple"},{"internalType":"bool","name":"_payInLzToken","type":"bool"}],"name":"quoteSend","outputs":[{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"msgFee","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"bytes32","name":"to","type":"bytes32"},{"internalType":"uint256","name":"amountLD","type":"uint256"},{"internalType":"uint256","name":"minAmountLD","type":"uint256"},{"internalType":"bytes","name":"extraOptions","type":"bytes"},{"internalType":"bytes","name":"composeMsg","type":"bytes"},{"internalType":"bytes","name":"oftCmd","type":"bytes"}],"internalType":"struct SendParam","name":"_sendParam","type":"tuple"},{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"_fee","type":"tuple"},{"internalType":"address","name":"_refundAddress","type":"address"}],"name":"send","outputs":[{"components":[{"internalType":"bytes32","name":"guid","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"components":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"internalType":"struct MessagingFee","name":"fee","type":"tuple"}],"internalType":"struct MessagingReceipt","name":"msgReceipt","type":"tuple"},{"components":[{"internalType":"uint256","name":"amountSentLD","type":"uint256"},{"internalType":"uint256","name":"amountReceivedLD","type":"uint256"}],"internalType":"struct OFTReceipt","name":"oftReceipt","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegate","type":"address"}],"name":"setDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"uint16","name":"msgType","type":"uint16"},{"internalType":"bytes","name":"options","type":"bytes"}],"internalType":"struct EnforcedOptionParam[]","name":"_enforcedOptions","type":"tuple[]"}],"name":"setEnforcedOptions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_msgInspector","type":"address"}],"name":"setMsgInspector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_eid","type":"uint32"},{"internalType":"bytes32","name":"_peer","type":"bytes32"}],"name":"setPeer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_preCrime","type":"address"}],"name":"setPreCrime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sharedDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60e06040523480156200001157600080fd5b5060405162003203380380620032038339810160408190526200003491620001d5565b806001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000073573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000099919062000214565b6001600160a01b03831660805282600660ff83161015620000cd576040516301e9714b60e41b815260040160405180910390fd5b620000da60068362000256565b620000e790600a62000375565b60a05250506001600160a01b03811660c052620001036200010b565b505062000386565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff16156200015c5760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b0390811614620001bc5780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b6001600160a01b0381168114620001bc57600080fd5b60008060408385031215620001e957600080fd5b8251620001f681620001bf565b60208401519092506200020981620001bf565b809150509250929050565b6000602082840312156200022757600080fd5b815160ff811681146200023957600080fd5b9392505050565b634e487b7160e01b600052601160045260246000fd5b60ff828116828216039081111562000272576200027262000240565b92915050565b600181815b80851115620002b95781600019048211156200029d576200029d62000240565b80851615620002ab57918102915b93841c93908002906200027d565b509250929050565b600082620002d25750600162000272565b81620002e15750600062000272565b8160018114620002fa5760028114620003055762000325565b600191505062000272565b60ff84111562000319576200031962000240565b50506001821b62000272565b5060208310610133831016604e8410600b84101617156200034a575081810a62000272565b62000356838362000278565b80600019048211156200036d576200036d62000240565b029392505050565b60006200023960ff841683620002c1565b60805160a05160c051612df96200040a60003960008181610695015281816119050152611b5a0152600081816104e601528181611a7b01528181611af00152611c420152600081816103f1015281816107e10152818161122e015281816114b7015281816117160152818161199f01528181611d770152611e300152612df96000f3fe6080604052600436106101f95760003560e01c8063857749b01161010d578063bd815db0116100a0578063d045a0dc1161006f578063d045a0dc14610633578063d424388514610646578063f2fde38b14610666578063fc0c546a14610686578063ff7bd03d146106b957600080fd5b8063bd815db0146105bf578063c4d66de8146105d2578063c7c7f5b3146105f2578063ca5eb5e11461061357600080fd5b8063b731ea0a116100dc578063b731ea0a1461052a578063b98bd0701461053f578063bb0b6a531461055f578063bc70b3541461059f57600080fd5b8063857749b0146104a35780638da5cb5b146104bf578063963efcaa146104d45780639f68b9641461051657600080fd5b80633b6f743b116101905780635e280f111161015f5780635e280f11146103df5780636fc1b31e14610413578063715018a6146104335780637d25a05e1461044857806382413eac1461048357600080fd5b80633b6f743b1461031e57806352ae28791461034b5780635535d4611461035e5780635a0dfe4d1461038b57600080fd5b8063156a0d0f116101cc578063156a0d0f146102a057806317442b70146102c75780631f5e1334146102e95780633400288b146102fe57600080fd5b80630d35b415146101fe578063111ecdad1461023657806313137d6514610263578063134d4f2514610278575b600080fd5b34801561020a57600080fd5b5061021e610219366004611fc9565b6106d9565b60405161022d9392919061204d565b60405180910390f35b34801561024257600080fd5b5061024b6107aa565b6040516001600160a01b03909116815260200161022d565b610276610271366004612155565b6107df565b005b34801561028457600080fd5b5061028d600281565b60405161ffff909116815260200161022d565b3480156102ac57600080fd5b506040805162b9270b60e21b8152600160208201520161022d565b3480156102d357600080fd5b506040805160018152600260208201520161022d565b3480156102f557600080fd5b5061028d600181565b34801561030a57600080fd5b5061027661031936600461220d565b61089f565b34801561032a57600080fd5b5061033e610339366004612245565b61090c565b60405161022d9190612296565b34801561035757600080fd5b503061024b565b34801561036a57600080fd5b5061037e6103793660046122bf565b610975565b60405161022d91906122f2565b34801561039757600080fd5b506103cf6103a636600461220d565b63ffffffff919091166000908152600080516020612da483398151915260205260409020541490565b604051901515815260200161022d565b3480156103eb57600080fd5b5061024b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561041f57600080fd5b5061027661042e366004612305565b610a50565b34801561043f57600080fd5b50610276610acc565b34801561045457600080fd5b5061046b61046336600461220d565b600092915050565b6040516001600160401b03909116815260200161022d565b34801561048f57600080fd5b506103cf61049e366004612322565b610ae0565b3480156104af57600080fd5b506040516006815260200161022d565b3480156104cb57600080fd5b5061024b610af5565b3480156104e057600080fd5b506105087f000000000000000000000000000000000000000000000000000000000000000081565b60405190815260200161022d565b34801561052257600080fd5b5060006103cf565b34801561053657600080fd5b5061024b610b1e565b34801561054b57600080fd5b5061027661055a3660046123cc565b610b47565b34801561056b57600080fd5b5061050861057a36600461240d565b63ffffffff166000908152600080516020612da4833981519152602052604090205490565b3480156105ab57600080fd5b5061037e6105ba366004612428565b610cc8565b6102766105cd3660046123cc565b610e5e565b3480156105de57600080fd5b506102766105ed366004612305565b610ff5565b610605610600366004612488565b61110c565b60405161022d9291906124f5565b34801561061f57600080fd5b5061027661062e366004612305565b611207565b610276610641366004612155565b61128d565b34801561065257600080fd5b50610276610661366004612305565b6112bc565b34801561067257600080fd5b50610276610681366004612305565b611330565b34801561069257600080fd5b507f000000000000000000000000000000000000000000000000000000000000000061024b565b3480156106c557600080fd5b506103cf6106d4366004612547565b61136e565b6040805180820190915260008082526020820152606061070c604051806040016040528060008152602001600081525090565b60408051808201825260008082526001600160401b03602080840182905284518381529081019094529195509182610767565b60408051808201909152600081526060602082015281526020019060019003908161073f5790505b50935060008061078c604089013560608a013561078760208c018c61240d565b61138c565b60408051808201909152918252602082015296989597505050505050565b6000807f41db8a78b0206aba5c54bcbfc2bda0d84082a84eb88e680379a57b9e9f653c005b546001600160a01b031692915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316331461082f576040516391ac5e4f60e01b81523360048201526024015b60405180910390fd5b6020870180359061084990610844908a61240d565b6113d0565b146108875761085b602088018861240d565b60405163309afaf360e21b815263ffffffff909116600482015260208801356024820152604401610826565b61089687878787878787611422565b50505050505050565b6108a7611589565b63ffffffff82166000818152600080516020612da4833981519152602081815260409283902085905582519384528301849052917f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b91015b60405180910390a1505050565b6040805180820190915260008082526020820152600061093c60408501356060860135610787602088018861240d565b91505060008061094c86846115bb565b9092509050610969610961602088018861240d565b838388611700565b93505050505b92915050565b63ffffffff821660009081527f8d2bda5d9f6ffb5796910376005392955773acee5548d0fcdb10e7c264ea00006020818152604080842061ffff86168552909152909120805460609291906109c990612579565b80601f01602080910402602001604051908101604052809291908181526020018280546109f590612579565b8015610a425780601f10610a1757610100808354040283529160200191610a42565b820191906000526020600020905b815481529060010190602001808311610a2557829003601f168201915b505050505091505092915050565b610a58611589565b7f41db8a78b0206aba5c54bcbfc2bda0d84082a84eb88e680379a57b9e9f653c0080546001600160a01b0319166001600160a01b03831690811782556040519081527ff0be4f1e87349231d80c36b33f9e8639658eeaf474014dee15a3e6a4d4414197906020015b60405180910390a15050565b610ad4611589565b610ade60006117e1565b565b6001600160a01b03811630145b949350505050565b6000807f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993006107cf565b6000807fefb041d771d6daaa55702fff6eb740d63ba559a75d2d1d3e151c78ff2480b6006107cf565b610b4f611589565b7f8d2bda5d9f6ffb5796910376005392955773acee5548d0fcdb10e7c264ea000060005b82811015610c9657610bb5848483818110610b9057610b906125ad565b9050602002810190610ba291906125c3565b610bb09060408101906125e3565b611852565b838382818110610bc757610bc76125ad565b9050602002810190610bd991906125c3565b610be79060408101906125e3565b836000878786818110610bfc57610bfc6125ad565b9050602002810190610c0e91906125c3565b610c1c90602081019061240d565b63ffffffff1663ffffffff1681526020019081526020016000206000878786818110610c4a57610c4a6125ad565b9050602002810190610c5c91906125c3565b610c6d906040810190602001612629565b61ffff168152602081019190915260400160002091610c8d91908361268c565b50600101610b73565b507fbe4864a8e820971c0247f5992e2da559595f7bf076a21cb5928d443d2a13b67483836040516108ff929190612774565b63ffffffff841660009081527f8d2bda5d9f6ffb5796910376005392955773acee5548d0fcdb10e7c264ea00006020818152604080842061ffff88168552909152822080546060939190610d1b90612579565b80601f0160208091040260200160405190810160405280929190818152602001828054610d4790612579565b8015610d945780601f10610d6957610100808354040283529160200191610d94565b820191906000526020600020905b815481529060010190602001808311610d7757829003601f168201915b505050505090508051600003610de55784848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610aed945050505050565b6000849003610df7579150610aed9050565b60028410610e4157610e098585611852565b80610e178560028189612858565b604051602001610e2993929190612882565b60405160208183030381529060405292505050610aed565b8484604051639a6d49cd60e01b81526004016108269291906128aa565b60005b81811015610f745736838383818110610e7c57610e7c6125ad565b9050602002810190610e8e91906128be565b9050610ece610ea0602083018361240d565b602083013563ffffffff919091166000908152600080516020612da483398151915260205260409020541490565b610ed85750610f6c565b3063d045a0dc60c08301358360a0810135610ef76101008301836125e3565b610f08610100890160e08a01612305565b610f166101208a018a6125e3565b6040518963ffffffff1660e01b8152600401610f3897969594939291906128ea565b6000604051808303818588803b158015610f5157600080fd5b505af1158015610f65573d6000803e3d6000fd5b5050505050505b600101610e61565b50336001600160a01b0316638e9e70996040518163ffffffff1660e01b8152600401600060405180830381865afa158015610fb3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610fdb9190810190612998565b604051638351eea760e01b815260040161082691906122f2565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b031660008115801561103a5750825b90506000826001600160401b031660011480156110565750303b155b905081158015611064575080155b156110825760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156110ac57845460ff60401b1916600160401b1785555b6110b586611899565b6110be866118ba565b831561110457845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b611114611f6a565b604080518082019091526000808252602082015260008061114b33604089013560608a013561114660208c018c61240d565b6118cb565b9150915060008061115c89846115bb565b909250905061118861117160208b018b61240d565b8383611182368d90038d018d612a39565b8b61196c565b60408051808201909152858152602080820186905282519298509096503391907f85496b760a4b7f8d66384b9df21b381f5d1b1e79f229a47aaf4c232edc2fe59a906111d6908d018d61240d565b6040805163ffffffff909216825260208201899052810187905260600160405180910390a350505050935093915050565b61120f611589565b60405163ca5eb5e160e01b81526001600160a01b0382811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063ca5eb5e190602401600060405180830381600087803b15801561127257600080fd5b505af1158015611286573d6000803e3d6000fd5b5050505050565b3330146112ad5760405163029a949d60e31b815260040160405180910390fd5b61089687878787878787610887565b6112c4611589565b7fefb041d771d6daaa55702fff6eb740d63ba559a75d2d1d3e151c78ff2480b60080546001600160a01b0319166001600160a01b03831690811782556040519081527fd48d879cef83a1c0bdda516f27b13ddb1b3f8bbac1c9e1511bb2a659c242776090602001610ac0565b611338611589565b6001600160a01b03811661136257604051631e4fbdf760e01b815260006004820152602401610826565b61136b816117e1565b50565b6000602082018035906113859061057a908561240d565b1492915050565b60008061139885611a77565b9150819050838110156113c8576040516371c4efed60e01b81526004810182905260248101859052604401610826565b935093915050565b63ffffffff81166000908152600080516020612da4833981519152602081905260408220548061141b5760405163f6ff4fb760e01b815263ffffffff85166004820152602401610826565b9392505050565b60006114346114318787611aae565b90565b905060006114608261144e6114498a8a611ac6565b611ae9565b61145b60208d018d61240d565b611b1e565b9050602886111561152757600061149d61148060608c0160408d01612a6b565b61148d60208d018d61240d565b846114988c8c611bbe565b611c09565b604051633e5ac80960e11b81529091506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690637cb59012906114f39086908d906000908790600401612a88565b600060405180830381600087803b15801561150d57600080fd5b505af1158015611521573d6000803e3d6000fd5b50505050505b6001600160a01b038216887fefed6d3500546b29533b128a29e3a94d70788727f0507505ac12eaf2e578fd9c61156060208d018d61240d565b6040805163ffffffff9092168252602082018690520160405180910390a3505050505050505050565b33611592610af5565b6001600160a01b031614610ade5760405163118cdaa760e01b8152336004820152602401610826565b606080600061161885602001356115d186611c3b565b6115de60a08901896125e3565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611c6792505050565b909350905060008161162b57600161162e565b60025b905061164e611640602088018861240d565b826105ba60808a018a6125e3565b7f41db8a78b0206aba5c54bcbfc2bda0d84082a84eb88e680379a57b9e9f653c008054919450906001600160a01b031680156116f55760405163043a78eb60e01b81526001600160a01b0382169063043a78eb906116b29089908990600401612ac3565b602060405180830381865afa1580156116cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f39190612ae8565b505b505050509250929050565b60408051808201909152600080825260208201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ddc28c586040518060a001604052808863ffffffff168152602001611763896113d0565b8152602001878152602001868152602001851515815250306040518363ffffffff1660e01b8152600401611798929190612b05565b6040805180830381865afa1580156117b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d89190612bae565b95945050505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b60006118616002828486612858565b61186a91612bca565b60f01c905060038114611894578282604051639a6d49cd60e01b81526004016108269291906128aa565b505050565b6118a1611ce1565b6118aa81611d2a565b6118b2611d3b565b61136b611d3b565b6118c2611ce1565b61136b81611d43565b6000806118d985858561138c565b604051632b8c49e360e01b81526001600160a01b038981166004830152602482018490529294509092507f000000000000000000000000000000000000000000000000000000000000000090911690632b8c49e390604401600060405180830381600087803b15801561194b57600080fd5b505af115801561195f573d6000803e3d6000fd5b5050505094509492505050565b611974611f6a565b60006119838460000151611d4b565b60208501519091501561199d5761199d8460200151611d73565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316632637a450826040518060a001604052808b63ffffffff1681526020016119ed8c6113d0565b81526020018a815260200189815260200160008960200151111515815250866040518463ffffffff1660e01b8152600401611a29929190612b05565b60806040518083038185885af1158015611a47573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611a6c9190612bfa565b979650505050505050565b60007f0000000000000000000000000000000000000000000000000000000000000000611aa48184612c61565b61096f9190612c83565b6000611abd6020828486612858565b61141b91612ca8565b6000611ad6602860208486612858565b611adf91612cc6565b60c01c9392505050565b600061096f7f00000000000000000000000000000000000000000000000000000000000000006001600160401b038416612c83565b60006001600160a01b038416611b345761dead93505b6040516318bf507760e01b81526001600160a01b038581166004830152602482018590527f000000000000000000000000000000000000000000000000000000000000000016906318bf507790604401600060405180830381600087803b158015611b9e57600080fd5b505af1158015611bb2573d6000803e3d6000fd5b50949695505050505050565b6060611bcd8260288186612858565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929695505050505050565b606084848484604051602001611c229493929190612cf4565b6040516020818303038152906040529050949350505050565b600061096f7f000000000000000000000000000000000000000000000000000000000000000083612c61565b8051606090151580611cb0578484604051602001611c9c92919091825260c01b6001600160c01b031916602082015260280190565b604051602081830303815290604052611cd7565b84843385604051602001611cc79493929190612d43565b6040516020818303038152906040525b9150935093915050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff16610ade57604051631afcd79f60e31b815260040160405180910390fd5b611d32611ce1565b6118aa81611e59565b610ade611ce1565b611338611ce1565b6000813414611d6f576040516304fb820960e51b8152346004820152602401610826565b5090565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e4fe1d946040518163ffffffff1660e01b8152600401602060405180830381865afa158015611dd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df79190612d86565b90506001600160a01b038116611e20576040516329b99a9560e11b815260040160405180910390fd5b611e556001600160a01b038216337f000000000000000000000000000000000000000000000000000000000000000085611e6a565b5050565b611e61611ce1565b61136b81611eca565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611ec4908590611ef9565b50505050565b611ed2611ce1565b6001600160a01b03811661120f57604051632d618d8160e21b815260040160405180910390fd5b600080602060008451602086016000885af180611f1c576040513d6000823e3d81fd5b50506000513d91508115611f34578060011415611f41565b6001600160a01b0384163b155b15611ec457604051635274afe760e01b81526001600160a01b0385166004820152602401610826565b60405180606001604052806000801916815260200160006001600160401b03168152602001611fac604051806040016040528060008152602001600081525090565b905290565b600060e08284031215611fc357600080fd5b50919050565b600060208284031215611fdb57600080fd5b81356001600160401b03811115611ff157600080fd5b610aed84828501611fb1565b60005b83811015612018578181015183820152602001612000565b50506000910152565b60008151808452612039816020860160208601611ffd565b601f01601f19169290920160200192915050565b8351815260208085015190820152600060a08201604060a0604085015281865180845260c08601915060c08160051b8701019350602080890160005b838110156120c85788870360bf190185528151805188528301518388018790526120b587890182612021565b9750509382019390820190600101612089565b50508751606088015250505060208501516080850152509050610aed565b600060608284031215611fc357600080fd5b60008083601f84011261210a57600080fd5b5081356001600160401b0381111561212157600080fd5b60208301915083602082850101111561213957600080fd5b9250929050565b6001600160a01b038116811461136b57600080fd5b600080600080600080600060e0888a03121561217057600080fd5b61217a89896120e6565b96506060880135955060808801356001600160401b038082111561219d57600080fd5b6121a98b838c016120f8565b909750955060a08a013591506121be82612140565b90935060c089013590808211156121d457600080fd5b506121e18a828b016120f8565b989b979a50959850939692959293505050565b803563ffffffff8116811461220857600080fd5b919050565b6000806040838503121561222057600080fd5b612229836121f4565b946020939093013593505050565b801515811461136b57600080fd5b6000806040838503121561225857600080fd5b82356001600160401b0381111561226e57600080fd5b61227a85828601611fb1565b925050602083013561228b81612237565b809150509250929050565b81518152602080830151908201526040810161096f565b803561ffff8116811461220857600080fd5b600080604083850312156122d257600080fd5b6122db836121f4565b91506122e9602084016122ad565b90509250929050565b60208152600061141b6020830184612021565b60006020828403121561231757600080fd5b813561141b81612140565b60008060008060a0858703121561233857600080fd5b61234286866120e6565b935060608501356001600160401b0381111561235d57600080fd5b612369878288016120f8565b909450925050608085013561237d81612140565b939692955090935050565b60008083601f84011261239a57600080fd5b5081356001600160401b038111156123b157600080fd5b6020830191508360208260051b850101111561213957600080fd5b600080602083850312156123df57600080fd5b82356001600160401b038111156123f557600080fd5b61240185828601612388565b90969095509350505050565b60006020828403121561241f57600080fd5b61141b826121f4565b6000806000806060858703121561243e57600080fd5b612447856121f4565b9350612455602086016122ad565b925060408501356001600160401b0381111561247057600080fd5b61247c878288016120f8565b95989497509550505050565b6000806000838503608081121561249e57600080fd5b84356001600160401b038111156124b457600080fd5b6124c087828801611fb1565b9450506040601f19820112156124d557600080fd5b5060208401915060608401356124ea81612140565b809150509250925092565b600060c082019050835182526001600160401b0360208501511660208301526040840151612530604084018280518252602090810151910152565b5082516080830152602083015160a083015261141b565b60006060828403121561255957600080fd5b61141b83836120e6565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061258d57607f821691505b602082108103611fc357634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60008235605e198336030181126125d957600080fd5b9190910192915050565b6000808335601e198436030181126125fa57600080fd5b8301803591506001600160401b0382111561261457600080fd5b60200191503681900382131561213957600080fd5b60006020828403121561263b57600080fd5b61141b826122ad565b601f821115611894576000816000526020600020601f850160051c8101602086101561266d5750805b601f850160051c820191505b8181101561110457828155600101612679565b6001600160401b038311156126a3576126a3612563565b6126b7836126b18354612579565b83612644565b6000601f8411600181146126eb57600085156126d35750838201355b600019600387901b1c1916600186901b178355611286565b600083815260209020601f19861690835b8281101561271c57868501358255602094850194600190920191016126fc565b50868210156127395760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60208082528181018390526000906040808401600586901b8501820187855b8881101561284a57878303603f190184528135368b9003605e190181126127b957600080fd5b8a01606063ffffffff6127cb836121f4565b16855261ffff6127dc8984016122ad565b168886015286820135601e198336030181126127f757600080fd5b9091018781019190356001600160401b0381111561281457600080fd5b80360383131561282357600080fd5b8188870152612835828701828561274b565b96890196955050509186019150600101612793565b509098975050505050505050565b6000808585111561286857600080fd5b8386111561287557600080fd5b5050820193919092039150565b60008451612894818460208901611ffd565b8201838582376000930192835250909392505050565b602081526000610aed60208301848661274b565b6000823561013e198336030181126125d957600080fd5b6001600160401b038116811461136b57600080fd5b63ffffffff6128f8896121f4565b1681526020880135602082015260006040890135612915816128d5565b6001600160401b03811660408401525087606083015260e0608083015261294060e08301878961274b565b6001600160a01b03861660a084015282810360c084015261296281858761274b565b9a9950505050505050505050565b604080519081016001600160401b038111828210171561299257612992612563565b60405290565b6000602082840312156129aa57600080fd5b81516001600160401b03808211156129c157600080fd5b818401915084601f8301126129d557600080fd5b8151818111156129e7576129e7612563565b604051601f8201601f19908116603f01168101908382118183101715612a0f57612a0f612563565b81604052828152876020848701011115612a2857600080fd5b611a6c836020830160208801611ffd565b600060408284031215612a4b57600080fd5b612a53612970565b82358152602083013560208201528091505092915050565b600060208284031215612a7d57600080fd5b813561141b816128d5565b60018060a01b038516815283602082015261ffff83166040820152608060608201526000612ab96080830184612021565b9695505050505050565b604081526000612ad66040830185612021565b82810360208401526117d88185612021565b600060208284031215612afa57600080fd5b815161141b81612237565b6040815263ffffffff8351166040820152602083015160608201526000604084015160a06080840152612b3b60e0840182612021565b90506060850151603f198483030160a0850152612b588282612021565b60809690960151151560c08501525050506001600160a01b039190911660209091015290565b600060408284031215612b9057600080fd5b612b98612970565b9050815181526020820151602082015292915050565b600060408284031215612bc057600080fd5b61141b8383612b7e565b6001600160f01b03198135818116916002851015612bf25780818660020360031b1b83161692505b505092915050565b600060808284031215612c0c57600080fd5b604051606081018181106001600160401b0382111715612c2e57612c2e612563565b604052825181526020830151612c43816128d5565b6020820152612c558460408501612b7e565b60408201529392505050565b600082612c7e57634e487b7160e01b600052601260045260246000fd5b500490565b808202811582820484141761096f57634e487b7160e01b600052601160045260246000fd5b8035602083101561096f57600019602084900360031b1b1692915050565b6001600160c01b03198135818116916008851015612bf25760089490940360031b84901b1690921692915050565b6001600160401b0360c01b8560c01b16815263ffffffff60e01b8460e01b16600882015282600c82015260008251612d3381602c850160208701611ffd565b91909101602c0195945050505050565b8481526001600160401b0360c01b8460c01b16602082015282602882015260008251612d76816048850160208701611ffd565b9190910160480195945050505050565b600060208284031215612d9857600080fd5b815161141b8161214056fe72ab1bc1039b79dc4724ffca13de82c96834302d3c7e0d4252232d4b2dd8f900a264697066735822122051314fe2191e5e0bf2142fd9e07be7b13940287d713c3af58101b5128772ff1f64736f6c634300081600330000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b0000000000000000000000009151434b16b9763660705744891fa906f660ecc5
Deployed Bytecode
0x6080604052600436106101f95760003560e01c8063857749b01161010d578063bd815db0116100a0578063d045a0dc1161006f578063d045a0dc14610633578063d424388514610646578063f2fde38b14610666578063fc0c546a14610686578063ff7bd03d146106b957600080fd5b8063bd815db0146105bf578063c4d66de8146105d2578063c7c7f5b3146105f2578063ca5eb5e11461061357600080fd5b8063b731ea0a116100dc578063b731ea0a1461052a578063b98bd0701461053f578063bb0b6a531461055f578063bc70b3541461059f57600080fd5b8063857749b0146104a35780638da5cb5b146104bf578063963efcaa146104d45780639f68b9641461051657600080fd5b80633b6f743b116101905780635e280f111161015f5780635e280f11146103df5780636fc1b31e14610413578063715018a6146104335780637d25a05e1461044857806382413eac1461048357600080fd5b80633b6f743b1461031e57806352ae28791461034b5780635535d4611461035e5780635a0dfe4d1461038b57600080fd5b8063156a0d0f116101cc578063156a0d0f146102a057806317442b70146102c75780631f5e1334146102e95780633400288b146102fe57600080fd5b80630d35b415146101fe578063111ecdad1461023657806313137d6514610263578063134d4f2514610278575b600080fd5b34801561020a57600080fd5b5061021e610219366004611fc9565b6106d9565b60405161022d9392919061204d565b60405180910390f35b34801561024257600080fd5b5061024b6107aa565b6040516001600160a01b03909116815260200161022d565b610276610271366004612155565b6107df565b005b34801561028457600080fd5b5061028d600281565b60405161ffff909116815260200161022d565b3480156102ac57600080fd5b506040805162b9270b60e21b8152600160208201520161022d565b3480156102d357600080fd5b506040805160018152600260208201520161022d565b3480156102f557600080fd5b5061028d600181565b34801561030a57600080fd5b5061027661031936600461220d565b61089f565b34801561032a57600080fd5b5061033e610339366004612245565b61090c565b60405161022d9190612296565b34801561035757600080fd5b503061024b565b34801561036a57600080fd5b5061037e6103793660046122bf565b610975565b60405161022d91906122f2565b34801561039757600080fd5b506103cf6103a636600461220d565b63ffffffff919091166000908152600080516020612da483398151915260205260409020541490565b604051901515815260200161022d565b3480156103eb57600080fd5b5061024b7f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b81565b34801561041f57600080fd5b5061027661042e366004612305565b610a50565b34801561043f57600080fd5b50610276610acc565b34801561045457600080fd5b5061046b61046336600461220d565b600092915050565b6040516001600160401b03909116815260200161022d565b34801561048f57600080fd5b506103cf61049e366004612322565b610ae0565b3480156104af57600080fd5b506040516006815260200161022d565b3480156104cb57600080fd5b5061024b610af5565b3480156104e057600080fd5b506105087f000000000000000000000000000000000000000000000000000000000000000181565b60405190815260200161022d565b34801561052257600080fd5b5060006103cf565b34801561053657600080fd5b5061024b610b1e565b34801561054b57600080fd5b5061027661055a3660046123cc565b610b47565b34801561056b57600080fd5b5061050861057a36600461240d565b63ffffffff166000908152600080516020612da4833981519152602052604090205490565b3480156105ab57600080fd5b5061037e6105ba366004612428565b610cc8565b6102766105cd3660046123cc565b610e5e565b3480156105de57600080fd5b506102766105ed366004612305565b610ff5565b610605610600366004612488565b61110c565b60405161022d9291906124f5565b34801561061f57600080fd5b5061027661062e366004612305565b611207565b610276610641366004612155565b61128d565b34801561065257600080fd5b50610276610661366004612305565b6112bc565b34801561067257600080fd5b50610276610681366004612305565b611330565b34801561069257600080fd5b507f0000000000000000000000009151434b16b9763660705744891fa906f660ecc561024b565b3480156106c557600080fd5b506103cf6106d4366004612547565b61136e565b6040805180820190915260008082526020820152606061070c604051806040016040528060008152602001600081525090565b60408051808201825260008082526001600160401b03602080840182905284518381529081019094529195509182610767565b60408051808201909152600081526060602082015281526020019060019003908161073f5790505b50935060008061078c604089013560608a013561078760208c018c61240d565b61138c565b60408051808201909152918252602082015296989597505050505050565b6000807f41db8a78b0206aba5c54bcbfc2bda0d84082a84eb88e680379a57b9e9f653c005b546001600160a01b031692915050565b7f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b0316331461082f576040516391ac5e4f60e01b81523360048201526024015b60405180910390fd5b6020870180359061084990610844908a61240d565b6113d0565b146108875761085b602088018861240d565b60405163309afaf360e21b815263ffffffff909116600482015260208801356024820152604401610826565b61089687878787878787611422565b50505050505050565b6108a7611589565b63ffffffff82166000818152600080516020612da4833981519152602081815260409283902085905582519384528301849052917f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b91015b60405180910390a1505050565b6040805180820190915260008082526020820152600061093c60408501356060860135610787602088018861240d565b91505060008061094c86846115bb565b9092509050610969610961602088018861240d565b838388611700565b93505050505b92915050565b63ffffffff821660009081527f8d2bda5d9f6ffb5796910376005392955773acee5548d0fcdb10e7c264ea00006020818152604080842061ffff86168552909152909120805460609291906109c990612579565b80601f01602080910402602001604051908101604052809291908181526020018280546109f590612579565b8015610a425780601f10610a1757610100808354040283529160200191610a42565b820191906000526020600020905b815481529060010190602001808311610a2557829003601f168201915b505050505091505092915050565b610a58611589565b7f41db8a78b0206aba5c54bcbfc2bda0d84082a84eb88e680379a57b9e9f653c0080546001600160a01b0319166001600160a01b03831690811782556040519081527ff0be4f1e87349231d80c36b33f9e8639658eeaf474014dee15a3e6a4d4414197906020015b60405180910390a15050565b610ad4611589565b610ade60006117e1565b565b6001600160a01b03811630145b949350505050565b6000807f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993006107cf565b6000807fefb041d771d6daaa55702fff6eb740d63ba559a75d2d1d3e151c78ff2480b6006107cf565b610b4f611589565b7f8d2bda5d9f6ffb5796910376005392955773acee5548d0fcdb10e7c264ea000060005b82811015610c9657610bb5848483818110610b9057610b906125ad565b9050602002810190610ba291906125c3565b610bb09060408101906125e3565b611852565b838382818110610bc757610bc76125ad565b9050602002810190610bd991906125c3565b610be79060408101906125e3565b836000878786818110610bfc57610bfc6125ad565b9050602002810190610c0e91906125c3565b610c1c90602081019061240d565b63ffffffff1663ffffffff1681526020019081526020016000206000878786818110610c4a57610c4a6125ad565b9050602002810190610c5c91906125c3565b610c6d906040810190602001612629565b61ffff168152602081019190915260400160002091610c8d91908361268c565b50600101610b73565b507fbe4864a8e820971c0247f5992e2da559595f7bf076a21cb5928d443d2a13b67483836040516108ff929190612774565b63ffffffff841660009081527f8d2bda5d9f6ffb5796910376005392955773acee5548d0fcdb10e7c264ea00006020818152604080842061ffff88168552909152822080546060939190610d1b90612579565b80601f0160208091040260200160405190810160405280929190818152602001828054610d4790612579565b8015610d945780601f10610d6957610100808354040283529160200191610d94565b820191906000526020600020905b815481529060010190602001808311610d7757829003601f168201915b505050505090508051600003610de55784848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610aed945050505050565b6000849003610df7579150610aed9050565b60028410610e4157610e098585611852565b80610e178560028189612858565b604051602001610e2993929190612882565b60405160208183030381529060405292505050610aed565b8484604051639a6d49cd60e01b81526004016108269291906128aa565b60005b81811015610f745736838383818110610e7c57610e7c6125ad565b9050602002810190610e8e91906128be565b9050610ece610ea0602083018361240d565b602083013563ffffffff919091166000908152600080516020612da483398151915260205260409020541490565b610ed85750610f6c565b3063d045a0dc60c08301358360a0810135610ef76101008301836125e3565b610f08610100890160e08a01612305565b610f166101208a018a6125e3565b6040518963ffffffff1660e01b8152600401610f3897969594939291906128ea565b6000604051808303818588803b158015610f5157600080fd5b505af1158015610f65573d6000803e3d6000fd5b5050505050505b600101610e61565b50336001600160a01b0316638e9e70996040518163ffffffff1660e01b8152600401600060405180830381865afa158015610fb3573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610fdb9190810190612998565b604051638351eea760e01b815260040161082691906122f2565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b031660008115801561103a5750825b90506000826001600160401b031660011480156110565750303b155b905081158015611064575080155b156110825760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff1916600117855583156110ac57845460ff60401b1916600160401b1785555b6110b586611899565b6110be866118ba565b831561110457845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b505050505050565b611114611f6a565b604080518082019091526000808252602082015260008061114b33604089013560608a013561114660208c018c61240d565b6118cb565b9150915060008061115c89846115bb565b909250905061118861117160208b018b61240d565b8383611182368d90038d018d612a39565b8b61196c565b60408051808201909152858152602080820186905282519298509096503391907f85496b760a4b7f8d66384b9df21b381f5d1b1e79f229a47aaf4c232edc2fe59a906111d6908d018d61240d565b6040805163ffffffff909216825260208201899052810187905260600160405180910390a350505050935093915050565b61120f611589565b60405163ca5eb5e160e01b81526001600160a01b0382811660048301527f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b169063ca5eb5e190602401600060405180830381600087803b15801561127257600080fd5b505af1158015611286573d6000803e3d6000fd5b5050505050565b3330146112ad5760405163029a949d60e31b815260040160405180910390fd5b61089687878787878787610887565b6112c4611589565b7fefb041d771d6daaa55702fff6eb740d63ba559a75d2d1d3e151c78ff2480b60080546001600160a01b0319166001600160a01b03831690811782556040519081527fd48d879cef83a1c0bdda516f27b13ddb1b3f8bbac1c9e1511bb2a659c242776090602001610ac0565b611338611589565b6001600160a01b03811661136257604051631e4fbdf760e01b815260006004820152602401610826565b61136b816117e1565b50565b6000602082018035906113859061057a908561240d565b1492915050565b60008061139885611a77565b9150819050838110156113c8576040516371c4efed60e01b81526004810182905260248101859052604401610826565b935093915050565b63ffffffff81166000908152600080516020612da4833981519152602081905260408220548061141b5760405163f6ff4fb760e01b815263ffffffff85166004820152602401610826565b9392505050565b60006114346114318787611aae565b90565b905060006114608261144e6114498a8a611ac6565b611ae9565b61145b60208d018d61240d565b611b1e565b9050602886111561152757600061149d61148060608c0160408d01612a6b565b61148d60208d018d61240d565b846114988c8c611bbe565b611c09565b604051633e5ac80960e11b81529091506001600160a01b037f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b1690637cb59012906114f39086908d906000908790600401612a88565b600060405180830381600087803b15801561150d57600080fd5b505af1158015611521573d6000803e3d6000fd5b50505050505b6001600160a01b038216887fefed6d3500546b29533b128a29e3a94d70788727f0507505ac12eaf2e578fd9c61156060208d018d61240d565b6040805163ffffffff9092168252602082018690520160405180910390a3505050505050505050565b33611592610af5565b6001600160a01b031614610ade5760405163118cdaa760e01b8152336004820152602401610826565b606080600061161885602001356115d186611c3b565b6115de60a08901896125e3565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611c6792505050565b909350905060008161162b57600161162e565b60025b905061164e611640602088018861240d565b826105ba60808a018a6125e3565b7f41db8a78b0206aba5c54bcbfc2bda0d84082a84eb88e680379a57b9e9f653c008054919450906001600160a01b031680156116f55760405163043a78eb60e01b81526001600160a01b0382169063043a78eb906116b29089908990600401612ac3565b602060405180830381865afa1580156116cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f39190612ae8565b505b505050509250929050565b60408051808201909152600080825260208201527f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b031663ddc28c586040518060a001604052808863ffffffff168152602001611763896113d0565b8152602001878152602001868152602001851515815250306040518363ffffffff1660e01b8152600401611798929190612b05565b6040805180830381865afa1580156117b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117d89190612bae565b95945050505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b60006118616002828486612858565b61186a91612bca565b60f01c905060038114611894578282604051639a6d49cd60e01b81526004016108269291906128aa565b505050565b6118a1611ce1565b6118aa81611d2a565b6118b2611d3b565b61136b611d3b565b6118c2611ce1565b61136b81611d43565b6000806118d985858561138c565b604051632b8c49e360e01b81526001600160a01b038981166004830152602482018490529294509092507f0000000000000000000000009151434b16b9763660705744891fa906f660ecc590911690632b8c49e390604401600060405180830381600087803b15801561194b57600080fd5b505af115801561195f573d6000803e3d6000fd5b5050505094509492505050565b611974611f6a565b60006119838460000151611d4b565b60208501519091501561199d5761199d8460200151611d73565b7f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b0316632637a450826040518060a001604052808b63ffffffff1681526020016119ed8c6113d0565b81526020018a815260200189815260200160008960200151111515815250866040518463ffffffff1660e01b8152600401611a29929190612b05565b60806040518083038185885af1158015611a47573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611a6c9190612bfa565b979650505050505050565b60007f0000000000000000000000000000000000000000000000000000000000000001611aa48184612c61565b61096f9190612c83565b6000611abd6020828486612858565b61141b91612ca8565b6000611ad6602860208486612858565b611adf91612cc6565b60c01c9392505050565b600061096f7f00000000000000000000000000000000000000000000000000000000000000016001600160401b038416612c83565b60006001600160a01b038416611b345761dead93505b6040516318bf507760e01b81526001600160a01b038581166004830152602482018590527f0000000000000000000000009151434b16b9763660705744891fa906f660ecc516906318bf507790604401600060405180830381600087803b158015611b9e57600080fd5b505af1158015611bb2573d6000803e3d6000fd5b50949695505050505050565b6060611bcd8260288186612858565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929695505050505050565b606084848484604051602001611c229493929190612cf4565b6040516020818303038152906040529050949350505050565b600061096f7f000000000000000000000000000000000000000000000000000000000000000183612c61565b8051606090151580611cb0578484604051602001611c9c92919091825260c01b6001600160c01b031916602082015260280190565b604051602081830303815290604052611cd7565b84843385604051602001611cc79493929190612d43565b6040516020818303038152906040525b9150935093915050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff16610ade57604051631afcd79f60e31b815260040160405180910390fd5b611d32611ce1565b6118aa81611e59565b610ade611ce1565b611338611ce1565b6000813414611d6f576040516304fb820960e51b8152346004820152602401610826565b5090565b60007f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b031663e4fe1d946040518163ffffffff1660e01b8152600401602060405180830381865afa158015611dd3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611df79190612d86565b90506001600160a01b038116611e20576040516329b99a9560e11b815260040160405180910390fd5b611e556001600160a01b038216337f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b85611e6a565b5050565b611e61611ce1565b61136b81611eca565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611ec4908590611ef9565b50505050565b611ed2611ce1565b6001600160a01b03811661120f57604051632d618d8160e21b815260040160405180910390fd5b600080602060008451602086016000885af180611f1c576040513d6000823e3d81fd5b50506000513d91508115611f34578060011415611f41565b6001600160a01b0384163b155b15611ec457604051635274afe760e01b81526001600160a01b0385166004820152602401610826565b60405180606001604052806000801916815260200160006001600160401b03168152602001611fac604051806040016040528060008152602001600081525090565b905290565b600060e08284031215611fc357600080fd5b50919050565b600060208284031215611fdb57600080fd5b81356001600160401b03811115611ff157600080fd5b610aed84828501611fb1565b60005b83811015612018578181015183820152602001612000565b50506000910152565b60008151808452612039816020860160208601611ffd565b601f01601f19169290920160200192915050565b8351815260208085015190820152600060a08201604060a0604085015281865180845260c08601915060c08160051b8701019350602080890160005b838110156120c85788870360bf190185528151805188528301518388018790526120b587890182612021565b9750509382019390820190600101612089565b50508751606088015250505060208501516080850152509050610aed565b600060608284031215611fc357600080fd5b60008083601f84011261210a57600080fd5b5081356001600160401b0381111561212157600080fd5b60208301915083602082850101111561213957600080fd5b9250929050565b6001600160a01b038116811461136b57600080fd5b600080600080600080600060e0888a03121561217057600080fd5b61217a89896120e6565b96506060880135955060808801356001600160401b038082111561219d57600080fd5b6121a98b838c016120f8565b909750955060a08a013591506121be82612140565b90935060c089013590808211156121d457600080fd5b506121e18a828b016120f8565b989b979a50959850939692959293505050565b803563ffffffff8116811461220857600080fd5b919050565b6000806040838503121561222057600080fd5b612229836121f4565b946020939093013593505050565b801515811461136b57600080fd5b6000806040838503121561225857600080fd5b82356001600160401b0381111561226e57600080fd5b61227a85828601611fb1565b925050602083013561228b81612237565b809150509250929050565b81518152602080830151908201526040810161096f565b803561ffff8116811461220857600080fd5b600080604083850312156122d257600080fd5b6122db836121f4565b91506122e9602084016122ad565b90509250929050565b60208152600061141b6020830184612021565b60006020828403121561231757600080fd5b813561141b81612140565b60008060008060a0858703121561233857600080fd5b61234286866120e6565b935060608501356001600160401b0381111561235d57600080fd5b612369878288016120f8565b909450925050608085013561237d81612140565b939692955090935050565b60008083601f84011261239a57600080fd5b5081356001600160401b038111156123b157600080fd5b6020830191508360208260051b850101111561213957600080fd5b600080602083850312156123df57600080fd5b82356001600160401b038111156123f557600080fd5b61240185828601612388565b90969095509350505050565b60006020828403121561241f57600080fd5b61141b826121f4565b6000806000806060858703121561243e57600080fd5b612447856121f4565b9350612455602086016122ad565b925060408501356001600160401b0381111561247057600080fd5b61247c878288016120f8565b95989497509550505050565b6000806000838503608081121561249e57600080fd5b84356001600160401b038111156124b457600080fd5b6124c087828801611fb1565b9450506040601f19820112156124d557600080fd5b5060208401915060608401356124ea81612140565b809150509250925092565b600060c082019050835182526001600160401b0360208501511660208301526040840151612530604084018280518252602090810151910152565b5082516080830152602083015160a083015261141b565b60006060828403121561255957600080fd5b61141b83836120e6565b634e487b7160e01b600052604160045260246000fd5b600181811c9082168061258d57607f821691505b602082108103611fc357634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052603260045260246000fd5b60008235605e198336030181126125d957600080fd5b9190910192915050565b6000808335601e198436030181126125fa57600080fd5b8301803591506001600160401b0382111561261457600080fd5b60200191503681900382131561213957600080fd5b60006020828403121561263b57600080fd5b61141b826122ad565b601f821115611894576000816000526020600020601f850160051c8101602086101561266d5750805b601f850160051c820191505b8181101561110457828155600101612679565b6001600160401b038311156126a3576126a3612563565b6126b7836126b18354612579565b83612644565b6000601f8411600181146126eb57600085156126d35750838201355b600019600387901b1c1916600186901b178355611286565b600083815260209020601f19861690835b8281101561271c57868501358255602094850194600190920191016126fc565b50868210156127395760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60208082528181018390526000906040808401600586901b8501820187855b8881101561284a57878303603f190184528135368b9003605e190181126127b957600080fd5b8a01606063ffffffff6127cb836121f4565b16855261ffff6127dc8984016122ad565b168886015286820135601e198336030181126127f757600080fd5b9091018781019190356001600160401b0381111561281457600080fd5b80360383131561282357600080fd5b8188870152612835828701828561274b565b96890196955050509186019150600101612793565b509098975050505050505050565b6000808585111561286857600080fd5b8386111561287557600080fd5b5050820193919092039150565b60008451612894818460208901611ffd565b8201838582376000930192835250909392505050565b602081526000610aed60208301848661274b565b6000823561013e198336030181126125d957600080fd5b6001600160401b038116811461136b57600080fd5b63ffffffff6128f8896121f4565b1681526020880135602082015260006040890135612915816128d5565b6001600160401b03811660408401525087606083015260e0608083015261294060e08301878961274b565b6001600160a01b03861660a084015282810360c084015261296281858761274b565b9a9950505050505050505050565b604080519081016001600160401b038111828210171561299257612992612563565b60405290565b6000602082840312156129aa57600080fd5b81516001600160401b03808211156129c157600080fd5b818401915084601f8301126129d557600080fd5b8151818111156129e7576129e7612563565b604051601f8201601f19908116603f01168101908382118183101715612a0f57612a0f612563565b81604052828152876020848701011115612a2857600080fd5b611a6c836020830160208801611ffd565b600060408284031215612a4b57600080fd5b612a53612970565b82358152602083013560208201528091505092915050565b600060208284031215612a7d57600080fd5b813561141b816128d5565b60018060a01b038516815283602082015261ffff83166040820152608060608201526000612ab96080830184612021565b9695505050505050565b604081526000612ad66040830185612021565b82810360208401526117d88185612021565b600060208284031215612afa57600080fd5b815161141b81612237565b6040815263ffffffff8351166040820152602083015160608201526000604084015160a06080840152612b3b60e0840182612021565b90506060850151603f198483030160a0850152612b588282612021565b60809690960151151560c08501525050506001600160a01b039190911660209091015290565b600060408284031215612b9057600080fd5b612b98612970565b9050815181526020820151602082015292915050565b600060408284031215612bc057600080fd5b61141b8383612b7e565b6001600160f01b03198135818116916002851015612bf25780818660020360031b1b83161692505b505092915050565b600060808284031215612c0c57600080fd5b604051606081018181106001600160401b0382111715612c2e57612c2e612563565b604052825181526020830151612c43816128d5565b6020820152612c558460408501612b7e565b60408201529392505050565b600082612c7e57634e487b7160e01b600052601260045260246000fd5b500490565b808202811582820484141761096f57634e487b7160e01b600052601160045260246000fd5b8035602083101561096f57600019602084900360031b1b1692915050565b6001600160c01b03198135818116916008851015612bf25760089490940360031b84901b1690921692915050565b6001600160401b0360c01b8560c01b16815263ffffffff60e01b8460e01b16600882015282600c82015260008251612d3381602c850160208701611ffd565b91909101602c0195945050505050565b8481526001600160401b0360c01b8460c01b16602082015282602882015260008251612d76816048850160208701611ffd565b9190910160480195945050505050565b600060208284031215612d9857600080fd5b815161141b8161214056fe72ab1bc1039b79dc4724ffca13de82c96834302d3c7e0d4252232d4b2dd8f900a264697066735822122051314fe2191e5e0bf2142fd9e07be7b13940287d713c3af58101b5128772ff1f64736f6c63430008160033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b0000000000000000000000009151434b16b9763660705744891fa906f660ecc5
-----Decoded View---------------
Arg [0] : _lzEndpoint (address): 0x6F475642a6e85809B1c36Fa62763669b1b48DD5B
Arg [1] : _token (address): 0x9151434b16b9763660705744891fA906F660EcC5
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b
Arg [1] : 0000000000000000000000009151434b16b9763660705744891fa906f660ecc5
Deployed Bytecode Sourcemap
384:2790:45:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6517:1258:27;;;;;;;;;;-1:-1:-1;6517:1258:27;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;4798:149;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;2732:32:52;;;2714:51;;2702:2;2687:18;4798:149:27;2568:203:52;4921:708:12;;;;;;:::i;:::-;;:::i;:::-;;2777:40:27;;;;;;;;;;;;2816:1;2777:40;;;;;4648:6:52;4636:19;;;4618:38;;4606:2;4591:18;2777:40:27;4474:188:52;3987:140:27;;;;;;;;;;-1:-1:-1;3987:140:27;;;-1:-1:-1;;;4837:52:52;;4118:1:27;4920:2:52;4905:18;;4898:59;4810:18;3987:140:27;4667:296:52;1951:257:14;;;;;;;;;;-1:-1:-1;1951:257:14;;;887:1:13;5175:34:52;;759:1:12;5240:2:52;5225:18;;5218:43;5111:18;1951:257:14;4968:299:52;2740:31:27;;;;;;;;;;;;2770:1;2740:31;;3028:202:11;;;;;;;;;;-1:-1:-1;3028:202:11;;;;;:::i;:::-;;:::i;8226:774:27:-;;;;;;;;;;-1:-1:-1;8226:774:27;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;2068:93:16:-;;;;;;;;;;-1:-1:-1;2149:4:16;2068:93;;1532:222:15;;;;;;;;;;-1:-1:-1;1532:222:15;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;16543:132:27:-;;;;;;;;;;-1:-1:-1;16543:132:27;;;;;:::i;:::-;2485:13:11;;;;;16625:4:27;2485:13:11;;;-1:-1:-1;;;;;;;;;;;2485:13:11;;;;;;16648:20:27;;16543:132;;;;7385:14:52;;7378:22;7360:41;;7348:2;7333:18;16543:132:27;7220:187:52;1035:46:11;;;;;;;;;;;;;;;5989:222:27;;;;;;;;;;-1:-1:-1;5989:222:27;;;;;:::i;:::-;;:::i;3155:101:31:-;;;;;;;;;;;;;:::i;4060:128:12:-;;;;;;;;;;-1:-1:-1;4060:128:12;;;;;:::i;:::-;4149:12;4060:128;;;;;;;;-1:-1:-1;;;;;8062:31:52;;;8044:50;;8032:2;8017:18;4060:128:12;7900:200:52;2566:216:12;;;;;;;;;;-1:-1:-1;2566:216:12;;;;;:::i;:::-;;:::i;5554:87:27:-;;;;;;;;;;-1:-1:-1;5554:87:27;;5633:1;8920:36:52;;8908:2;8893:18;5554:87:27;8778:184:52;2441:144:31;;;;;;;;;;;;;:::i;2434:46:27:-;;;;;;;;;;;;;;;;;;9113:25:52;;;9101:2;9086:18;2434:46:27;8967:177:52;1199:94:45;;;;;;;;;;-1:-1:-1;1258:4:45;1199:94;;1596:180:16;;;;;;;;;;;;;:::i;2513:600:15:-;;;;;;;;;;-1:-1:-1;2513:600:15;;;;;:::i;:::-;;:::i;2342:163:11:-;;;;;;;;;;-1:-1:-1;2342:163:11;;;;;:::i;:::-;2485:13;;2400:7;2485:13;;;-1:-1:-1;;;;;;;;;;;2485:13:11;;;;;;;2342:163;3872:1058:15;;;;;;;;;;-1:-1:-1;3872:1058:15;;;;;:::i;:::-;;:::i;2978:1333:16:-;;;;;;:::i;:::-;;:::i;764:135:45:-;;;;;;;;;;-1:-1:-1;764:135:45;;;;;:::i;:::-;;:::i;9688:1340:27:-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;4123:105:11:-;;;;;;;;;;-1:-1:-1;4123:105:11;;;;;:::i;:::-;;:::i;4959:409:16:-;;;;;;:::i;:::-;;:::i;2293:226::-;;;;;;;;;;-1:-1:-1;2293:226:16;;;;;:::i;:::-;;:::i;3405:215:31:-;;;;;;;;;;-1:-1:-1;3405:215:31;;;;;:::i;:::-;;:::i;476:88:45:-;;;;;;;;;;-1:-1:-1;550:6:45;476:88;;3324:149:12;;;;;;;;;;-1:-1:-1;3324:149:12;;;;;:::i;:::-;;:::i;6517:1258:27:-;-1:-1:-1;;;;;;;;;;;;;;;;;6669:35:27;6706:28;-1:-1:-1;;;;;;;;;;;;;;;;;;;6706:28:27;6924:34;;;;;;;;-1:-1:-1;6924:34:27;;;-1:-1:-1;;;;;6924:34:27;;;;;;;7075:21;;;;;;;;;;;6924:34;;-1:-1:-1;;;7075:21:27;;;-1:-1:-1;;;;;;;;;;;;;;;;;7075:21:27;;;;;;;;;;;;;;;-1:-1:-1;7059:37:27;-1:-1:-1;7533:20:27;;7583:120;7607:19;;;;7640:22;;;;7676:17;;;;7607:10;7676:17;:::i;:::-;7583:10;:120::i;:::-;7726:42;;;;;;;;;;;;;;;;6517:1258;;;;-1:-1:-1;;;;;;6517:1258:27:o;4798:149::-;4843:7;;2993:25;4889:20;4926:14;-1:-1:-1;;;;;4926:14:27;;4798:149;-1:-1:-1;;4798:149:27:o;4921:708:12:-;5234:8;-1:-1:-1;;;;;5226:31:12;5247:10;5226:31;5222:68;;5266:24;;-1:-1:-1;;;5266:24:12;;5279:10;5266:24;;;2714:51:52;2687:18;;5266:24:12;;;;;;;;5222:68;5426:14;;;;;;5390:32;;5407:14;;5426:7;5407:14;:::i;:::-;5390:16;:32::i;:::-;:50;5386:103;;5458:14;;;;:7;:14;:::i;:::-;5449:40;;-1:-1:-1;;;5449:40:12;;13337:10:52;13325:23;;;5449:40:12;;;13307:42:52;5474:14:12;;;;13365:18:52;;;13358:34;13280:18;;5449:40:12;13135:263:52;5386:103:12;5563:59;5574:7;5583:5;5590:8;;5600:9;5611:10;;5563;:59::i;:::-;4921:708;;;;;;;:::o;3028:202:11:-;2334:13:31;:11;:13::i;:::-;3167::11::1;::::0;::::1;3108:25;3167:13:::0;;;-1:-1:-1;;;;;;;;;;;3167:13:11::1;::::0;;;;;;;;:21;;;3203:20;;13307:42:52;;;13365:18;;13358:34;;;926:26:11;3203:20:::1;::::0;13280:18:52;3203:20:11::1;;;;;;;;3098:132;3028:202:::0;;:::o;8226:774:27:-;-1:-1:-1;;;;;;;;;;;;;;;;;8560:24:27;8588:74;8599:19;;;;8620:22;;;;8644:17;;;;8599:10;8644:17;:::i;8588:74::-;8557:105;;;8751:20;8773;8797:49;8817:10;8829:16;8797:19;:49::i;:::-;8750:96;;-1:-1:-1;8750:96:27;-1:-1:-1;8935:58:27;8942:17;;;;:10;:17;:::i;:::-;8961:7;8970;8979:13;8935:6;:58::i;:::-;8928:65;;;;;8226:774;;;;;:::o;1532:222:15:-;1714:23;;;1632:33;1714:23;;;1151:36;1714:23;;;;;;;;:33;;;;;;;;;;;1707:40;;1608:12;;1151:36;1714:33;1707:40;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1532:222;;;;:::o;5989::27:-;2334:13:31;:11;:13::i;:::-;2993:25:27;6129:30;;-1:-1:-1;;;;;;6129:30:27::1;-1:-1:-1::0;;;;;6129:30:27;::::1;::::0;;::::1;::::0;;6174::::1;::::0;2714:51:52;;;6174:30:27::1;::::0;2702:2:52;2687:18;6174:30:27::1;;;;;;;;6062:149;5989:222:::0;:::o;3155:101:31:-;2334:13;:11;:13::i;:::-;3219:30:::1;3246:1;3219:18;:30::i;:::-;3155:101::o:0;2566:216:12:-;-1:-1:-1;;;;;2751:24:12;;2770:4;2751:24;2566:216;;;;;;;:::o;2441:144:31:-;2487:7;;1313:22;2533:20;1192:159;1596:180:16;1648:7;;1200:41;1708:34;1050:207;2513:600:15;2334:13:31;:11;:13::i;:::-;1151:36:15;2625:33:::1;2700:356;2720:27:::0;;::::1;2700:356;;;2882:48;2902:16;;2919:1;2902:19;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:27;::::0;::::1;::::0;::::1;::::0;::::1;:::i;:::-;2882:19;:48::i;:::-;3018:16;;3035:1;3018:19;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:27;::::0;::::1;::::0;::::1;::::0;::::1;:::i;:::-;2944:1:::0;:17:::1;2962:16:::0;;2979:1;2962:19;;::::1;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:23;::::0;::::1;::::0;::::1;::::0;::::1;:::i;:::-;2944:42;;;;;;;;;;;;;;;:71;2987:16;;3004:1;2987:19;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;:27;::::0;;;;;::::1;;;:::i;:::-;2944:71;;::::0;;::::1;::::0;::::1;::::0;;;;;;-1:-1:-1;2944:71:15;;:101:::1;::::0;;:71;:101:::1;:::i;:::-;-1:-1:-1::0;2749:3:15::1;;2700:356;;;;3071:35;3089:16;;3071:35;;;;;;;:::i;3872:1058::-:0;4138:23;;;4039:33;4138:23;;;1151:36;4138:23;;;;;;;;:33;;;;;;;;;;4114:57;;4015:12;;4039:33;4138;4114:57;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4300:8;:15;4319:1;4300:20;4296:46;;4329:13;;4322:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;4322:20:15;;-1:-1:-1;4322:20:15;;-1:-1:-1;;;;;4322:20:15;4296:46;4427:1;4403:25;;;4399:46;;4437:8;-1:-1:-1;4430:15:15;;-1:-1:-1;4430:15:15;4399:46;4592:1;4568:25;;4564:267;;4609:34;4629:13;;4609:19;:34::i;:::-;4792:8;4802:17;:13;4816:1;4802:13;;:17;:::i;:::-;4779:41;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;4772:48;;;;;;4564:267;4909:13;;4894:29;;-1:-1:-1;;;4894:29:15;;;;;;;;;:::i;2978:1333:16:-;3079:9;3074:1037;3094:19;;;3074:1037;;;3134:29;3166:8;;3175:1;3166:11;;;;;;;:::i;:::-;;;;;;;;;;;;:::i;:::-;3134:43;-1:-1:-1;3260:50:16;3267:20;;;;3134:43;3267:20;:::i;:::-;3289;;;;2485:13:11;;;;;16625:4:27;2485:13:11;;;-1:-1:-1;;;;;;;;;;;2485:13:11;;;;;;16648:20:27;;16543:132;3260:50:16;3255:65;;3312:8;;;3255:65;3882:4;:22;3913:12;;;;:6;3976:11;;;;4005:14;;;;3913:6;4005:14;:::i;:::-;4037:15;;;;;;;;:::i;:::-;4070:16;;;;:6;:16;:::i;:::-;3882:218;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3120:991;3074:1037;3115:3;;3074:1037;;;;4268:10;-1:-1:-1;;;;;4258:43:16;;:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;4258:45:16;;;;;;;;;;;;:::i;:::-;4241:63;;-1:-1:-1;;;4241:63:16;;;;;;;;:::i;764:135:45:-;8870:21:32;4302:15;;-1:-1:-1;;;4302:15:32;;;;4301:16;;-1:-1:-1;;;;;4348:14:32;4158:30;4726:16;;:34;;;;;4746:14;4726:34;4706:54;;4770:17;4790:11;-1:-1:-1;;;;;4790:16:32;4805:1;4790:16;:50;;;;-1:-1:-1;4818:4:32;4810:25;:30;4790:50;4770:70;;4856:12;4855:13;:30;;;;;4873:12;4872:13;4855:30;4851:91;;;4908:23;;-1:-1:-1;;;4908:23:32;;;;;;;;;;;4851:91;4951:18;;-1:-1:-1;;4951:18:32;4968:1;4951:18;;;4979:67;;;;5013:22;;-1:-1:-1;;;;5013:22:32;-1:-1:-1;;;5013:22:32;;;4979:67;832:25:45::1;847:9;832:14;:25::i;:::-;867;882:9;867:14;:25::i;:::-;5070:14:32::0;5066:101;;;5100:23;;-1:-1:-1;;;;5100:23:32;;;5142:14;;-1:-1:-1;8044:50:52;;5142:14:32;;8032:2:52;8017:18;5142:14:32;;;;;;;5066:101;4092:1081;;;;;764:135:45;:::o;9688:1340:27:-;9849:34;;:::i;:::-;-1:-1:-1;;;;;;;;;;;;;;;;;10247:20:27;;10297:140;10317:10;10341:19;;;;10374:22;;;;10410:17;;;;10341:10;10410:17;:::i;:::-;10297:6;:140::i;:::-;10246:191;;;;10526:20;10548;10572:49;10592:10;10604:16;10572:19;:49::i;:::-;10525:96;;-1:-1:-1;10525:96:27;-1:-1:-1;10744:66:27;10752:17;;;;:10;:17;:::i;:::-;10771:7;10780;10744:66;;;;;;;10789:4;10744:66;:::i;:::-;10795:14;10744:7;:66::i;:::-;10876:42;;;;;;;;;;;;;;;;;;;10942:15;;10731:79;;-1:-1:-1;10876:42:27;;-1:-1:-1;10978:10:27;;10942:15;10934:87;;10959:17;;;;:10;:17;:::i;:::-;10934:87;;;23547:10:52;23535:23;;;23517:42;;23590:2;23575:18;;23568:34;;;23618:18;;23611:34;;;23505:2;23490:18;10934:87:27;;;;;;;9915:1113;;;;9688:1340;;;;;;:::o;4123:105:11:-;2334:13:31;:11;:13::i;:::-;4190:31:11::1;::::0;-1:-1:-1;;;4190:31:11;;-1:-1:-1;;;;;2732:32:52;;;4190:31:11::1;::::0;::::1;2714:51:52::0;4190:8:11::1;:20;::::0;::::1;::::0;2687:18:52;;4190:31:11::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;4123:105:::0;:::o;4959:409:16:-;5238:10;5260:4;5238:27;5234:50;;5274:10;;-1:-1:-1;;;5274:10:16;;;;;;;;;;;5234:50;5294:67;5313:7;5322:5;5329:8;;5339:9;5350:10;;5294:18;:67::i;2293:226::-;2334:13:31;:11;:13::i;:::-;1200:41:16;2453:22;;-1:-1:-1;;;;;;2453:22:16::1;-1:-1:-1::0;;;;;2453:22:16;::::1;::::0;;::::1;::::0;;2490::::1;::::0;2714:51:52;;;2490:22:16::1;::::0;2702:2:52;2687:18;2490:22:16::1;2568:203:52::0;3405:215:31;2334:13;:11;:13::i;:::-;-1:-1:-1;;;;;3489:22:31;::::1;3485:91;;3534:31;::::0;-1:-1:-1;;;3534:31:31;;3562:1:::1;3534:31;::::0;::::1;2714:51:52::0;2687:18;;3534:31:31::1;2568:203:52::0;3485:91:31::1;3585:28;3604:8;3585:18;:28::i;:::-;3405:215:::0;:::o;3324:149:12:-;3406:4;3453:13;;;;;;3429:20;;3435:13;;3453:6;3435:13;:::i;3429:20::-;:37;;3324:149;-1:-1:-1;;3324:149:12:o;18560:668:27:-;18702:20;18724:24;18898:22;18910:9;18898:11;:22::i;:::-;18883:37;;19046:12;19027:31;;19128:12;19109:16;:31;19105:117;;;19163:48;;-1:-1:-1;;;19163:48:27;;;;;23830:25:52;;;23871:18;;;23864:34;;;23803:18;;19163:48:27;23656:248:52;19105:117:27;18560:668;;;;;;:::o;3528:257:11:-;3691:13;;;3598:7;3691:13;;;-1:-1:-1;;;;;;;;;;;3691:13:11;;;;;;;;;3714:43;;3745:12;;-1:-1:-1;;;3745:12:11;;24083:10:52;24071:23;;3745:12:11;;;24053:42:52;24026:18;;3745:12:11;23909:192:52;3714:43:11;3774:4;3528:257;-1:-1:-1;;;3528:257:11:o;13336:1806:27:-;13813:17;13833:36;:17;:8;;:15;:17::i;:::-;2891:2:30;2780:123;13833:36:27;13813:56;;14002:24;14029:62;14037:9;14048:26;14054:19;:8;;:17;:19::i;:::-;14048:5;:26::i;:::-;14076:14;;;;:7;:14;:::i;:::-;14029:7;:62::i;:::-;14002:89;-1:-1:-1;243:2:30;-1:-1:-1;;14102:955:27;;;14206:23;14232:175;14275:13;;;;;;;;:::i;:::-;14306:14;;;;:7;:14;:::i;:::-;14338:16;14372:21;:8;;:19;:21::i;:::-;14232:25;:175::i;:::-;14954:92;;-1:-1:-1;;;14954:92:27;;14206:201;;-1:-1:-1;;;;;;14954:8:27;:20;;;;:92;;14975:9;;14986:5;;14993:1;;14206:201;;14954:92;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14129:928;14102:955;-1:-1:-1;;;;;15072:63:27;;15084:5;15072:63;15091:14;;;;:7;:14;:::i;:::-;15072:63;;;13337:10:52;13325:23;;;13307:42;;13380:2;13365:18;;13358:34;;;13280:18;15072:63:27;;;;;;;13639:1503;;13336:1806;;;;;;;:::o;2658:162:31:-;966:10:33;2717:7:31;:5;:7::i;:::-;-1:-1:-1;;;;;2717:23:31;;2713:101;;2763:40;;-1:-1:-1;;;2763:40:31;;966:10:33;2763:40:31;;;2714:51:52;2687:18;;2763:40:31;2568:203:52;11322:1496:27;11454:20;11476;11508:15;11679:324;11711:10;:13;;;11738:16;11744:9;11738:5;:16::i;:::-;11972:21;;;;:10;:21;:::i;:::-;11679:324;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;11679:18:27;;-1:-1:-1;;;11679:324:27:i;:::-;11655:348;;-1:-1:-1;11655:348:27;-1:-1:-1;12083:14:27;11655:348;12100:33;;2770:1;12100:33;;;2816:1;12100:33;12083:50;-1:-1:-1;12255:67:27;12270:17;;;;:10;:17;:::i;:::-;12289:7;12298:23;;;;:10;:23;:::i;12255:67::-;2993:25;12638:14;;12245:77;;-1:-1:-1;2993:25:27;-1:-1:-1;;;;;12638:14:27;12732:23;;12728:83;;12757:54;;-1:-1:-1;;;12757:54:27;;-1:-1:-1;;;;;12757:36:27;;;;;:54;;12794:7;;12803;;12757:54;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;12728:83;11498:1320;;;;11322:1496;;;;;:::o;2550:391:13:-;-1:-1:-1;;;;;;;;;;;;;;;;;2771:8:13;-1:-1:-1;;;;;2771:14:13;;2803:86;;;;;;;;2819:7;2803:86;;;;;;2828:25;2845:7;2828:16;:25::i;:::-;2803:86;;;;2855:8;2803:86;;;;2865:8;2803:86;;;;2875:13;2803:86;;;;;2915:4;2771:163;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2752:182;2550:391;-1:-1:-1;;;;;2550:391:13:o;3774:248:31:-;1313:22;3923:8;;-1:-1:-1;;;;;;3941:19:31;;-1:-1:-1;;;;;3941:19:31;;;;;;;;3975:40;;3923:8;;;;;3975:40;;3847:24;;3975:40;3837:185;;3774:248;:::o;5070:218:15:-;5156:18;5191:13;5202:1;5156:18;5191:8;;:13;:::i;:::-;5184:21;;;:::i;:::-;5177:29;;;-1:-1:-1;1003:1:15;5220:28;;5216:65;;5272:8;;5257:24;;-1:-1:-1;;;5257:24:15;;;;;;;;;:::i;5216:65::-;5146:142;5070:218;;:::o;4539:183:27:-;6931:20:32;:18;:20::i;:::-;4618:22:27::1;4630:9;4618:11;:22::i;:::-;4650:30;:28;:30::i;:::-;4690:25;:23;:25::i;1847:127:31:-:0;6931:20:32;:18;:20::i;:::-;1929:38:31::1;1954:12;1929:24;:38::i;1776:583:45:-:0;1937:20;1959:24;2030:44;2041:9;2052:12;2066:7;2030:10;:44::i;:::-;2310:42;;-1:-1:-1;;;2310:42:45;;-1:-1:-1;;;;;27695:32:52;;;2310:42:45;;;27677:51:52;27744:18;;;27737:34;;;1995:79:45;;-1:-1:-1;1995:79:45;;-1:-1:-1;2310:6:45;:21;;;;;;27650:18:52;;2310:42:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1776:583;;;;;;;:::o;3700:766:13:-;3901:31;;:::i;:::-;4066:20;4089:26;4100:4;:14;;;4089:10;:26::i;:::-;4129:15;;;;4066:49;;-1:-1:-1;4129:19:13;4125:53;;4150:28;4162:4;:15;;;4150:11;:28::i;:::-;4267:8;-1:-1:-1;;;;;4267:13:13;;4289:12;4321:92;;;;;;;;4337:7;4321:92;;;;;;4346:25;4363:7;4346:16;:25::i;:::-;4321:92;;;;4373:8;4321:92;;;;4383:8;4321:92;;;;4411:1;4393:4;:15;;;:19;4321:92;;;;;4431:14;4267:192;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4189:270;3700:766;-1:-1:-1;;;;;;;3700:766:13:o;17069:172:27:-;17140:16;17213:21;17176:33;17213:21;17176:9;:33;:::i;:::-;17175:59;;;;:::i;1573:123:30:-;1633:7;1667:21;188:2;1633:7;1667:4;;:21;:::i;:::-;1659:30;;;:::i;1874:152::-;1936:6;1975:42;243:2;188;1975:4;;:42;:::i;:::-;1968:50;;;:::i;:::-;1961:58;;;1874:152;-1:-1:-1;;;1874:152:30:o;17465:139:27:-;17529:16;17564:33;17576:21;-1:-1:-1;;;;;17564:33:27;;;:::i;2694:478:45:-;2828:24;-1:-1:-1;;;;;2868:19:45;;2864:46;;2903:6;2889:21;;2864:46;3006:37;;-1:-1:-1;;;3006:37:45;;-1:-1:-1;;;;;27695:32:52;;;3006:37:45;;;27677:51:52;27744:18;;;27737:34;;;3006:6:45;:21;;;;27650:18:52;;3006:37:45;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3156:9:45;;2694:478;-1:-1:-1;;;;;;2694:478:45:o;2186:130:30:-;2250:12;2281:28;:4;243:2;2281:4;;:28;:::i;:::-;2274:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2274:35:30;;2186:130;-1:-1:-1;;;;;;2186:130:30:o;640:284:29:-;824:17;877:6;885:7;894:9;905:11;860:57;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;853:64;;640:284;;;;;;:::o;17828:147:27:-;17893:15;17934:33;17946:21;17934:9;:33;:::i;598:506:30:-;791:18;;732:17;;791:22;;;934:163;;1074:7;1083:13;1057:40;;;;;;;;30284:19:52;;;30359:3;30337:16;-1:-1:-1;;;;;;30333:51:52;30328:2;30319:12;;30312:73;30410:2;30401:12;;30129:290;1057:40:30;;;;;;;;;;;;;934:163;;;976:7;985:13;1017:10;1030:11;959:83;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;934:163;927:170;;598:506;;;;;;:::o;7084:141:32:-;8870:21;8560:40;-1:-1:-1;;;8560:40:32;;;;7146:73;;7191:17;;-1:-1:-1;;;7191:17:32;;;;;;;;;;;1456:189:14;6931:20:32;:18;:20::i;:::-;1532:26:14::1;1548:9;1532:15;:26::i;1438:68:16:-:0;6931:20:32;:18;:20::i;1980:235:31:-;6931:20:32;:18;:20::i;5162:191:13:-;5228:17;5274:10;5261:9;:23;5257:62;;5293:26;;-1:-1:-1;;;5293:26:13;;5309:9;5293:26;;;9113:25:52;9086:18;;5293:26:13;8967:177:52;5257:62:13;-1:-1:-1;5336:10:13;5162:191::o;5730:410::-;5883:15;5901:8;-1:-1:-1;;;;;5901:16:13;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5883:36;-1:-1:-1;;;;;;5933:21:13;;5929:54;;5963:20;;-1:-1:-1;;;5963:20:13;;;;;;;;;;;5929:54;6057:76;-1:-1:-1;;;;;6057:32:13;;6090:10;6110:8;6121:11;6057:32;:76::i;:::-;5789:351;5730:410;:::o;1787:123:11:-;6931:20:32;:18;:20::i;:::-;1867:36:11::1;1893:9;1867:25;:36::i;1618:188:42:-:0;1745:53;;;-1:-1:-1;;;;;31475:15:52;;;1745:53:42;;;31457:34:52;31527:15;;31507:18;;;31500:43;31559:18;;;;31552:34;;;1745:53:42;;;;;;;;;;31392:18:52;;;;1745:53:42;;;;;;;;-1:-1:-1;;;;;1745:53:42;-1:-1:-1;;;1745:53:42;;;1718:81;;1738:5;;1718:19;:81::i;:::-;1618:188;;;;:::o;1916:191:11:-;6931:20:32;:18;:20::i;:::-;-1:-1:-1;;;;;2010:23:11;::::1;2006:53;;2042:17;;-1:-1:-1::0;;;2042:17:11::1;;;;;;;;;;;7686:720:42::0;7766:18;7794:19;7932:4;7929:1;7922:4;7916:11;7909:4;7903;7899:15;7896:1;7889:5;7882;7877:60;7989:7;7979:176;;8033:4;8027:11;8078:16;8075:1;8070:3;8055:40;8124:16;8119:3;8112:29;7979:176;-1:-1:-1;;8232:1:42;8226:8;8182:16;;-1:-1:-1;8258:15:42;;:68;;8310:11;8325:1;8310:16;;8258:68;;;-1:-1:-1;;;;;8276:26:42;;;:31;8258:68;8254:146;;;8349:40;;-1:-1:-1;;;8349:40:42;;-1:-1:-1;;;;;2732:32:52;;8349:40:42;;;2714:51:52;2687:18;;8349:40:42;2568:203:52;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;14:158:52:-;76:5;121:3;112:6;107:3;103:16;99:26;96:46;;;138:1;135;128:12;96:46;-1:-1:-1;160:6:52;14:158;-1:-1:-1;14:158:52:o;177:360::-;265:6;318:2;306:9;297:7;293:23;289:32;286:52;;;334:1;331;324:12;286:52;374:9;361:23;-1:-1:-1;;;;;399:6:52;396:30;393:50;;;439:1;436;429:12;393:50;462:69;523:7;514:6;503:9;499:22;462:69;:::i;696:250::-;781:1;791:113;805:6;802:1;799:13;791:113;;;881:11;;;875:18;862:11;;;855:39;827:2;820:10;791:113;;;-1:-1:-1;;938:1:52;920:16;;913:27;696:250::o;951:271::-;993:3;1031:5;1025:12;1058:6;1053:3;1046:19;1074:76;1143:6;1136:4;1131:3;1127:14;1120:4;1113:5;1109:16;1074:76;:::i;:::-;1204:2;1183:15;-1:-1:-1;;1179:29:52;1170:39;;;;1211:4;1166:50;;951:271;-1:-1:-1;;951:271:52:o;1227:1336::-;616:12;;604:25;;678:4;667:16;;;661:23;645:14;;;638:47;1593:4;1641:3;1626:19;;1718:2;1756:3;1751:2;1740:9;1736:18;1729:31;1780:6;1815;1809:13;1846:6;1838;1831:22;1884:3;1873:9;1869:19;1862:26;;1947:3;1937:6;1934:1;1930:14;1919:9;1915:30;1911:40;1897:54;;1970:4;2009;2001:6;1997:17;2032:1;2042:429;2056:6;2053:1;2050:13;2042:429;;;2121:22;;;-1:-1:-1;;2117:37:52;2105:50;;2178:13;;2219:9;;2204:25;;2268:11;;2262:18;2300:15;;;2293:27;;;2343:48;2375:15;;;2262:18;2343:48;:::i;:::-;2333:58;-1:-1:-1;;2449:12:52;;;;2414:15;;;;2078:1;2071:9;2042:429;;;-1:-1:-1;;616:12:52;;2553:2;2538:18;;604:25;-1:-1:-1;;;678:4:52;667:16;;661:23;645:14;;;638:47;-1:-1:-1;2488:6:52;-1:-1:-1;2503:54:52;542:149;2776:154;2835:5;2880:2;2871:6;2866:3;2862:16;2858:25;2855:45;;;2896:1;2893;2886:12;2935:347;2986:8;2996:6;3050:3;3043:4;3035:6;3031:17;3027:27;3017:55;;3068:1;3065;3058:12;3017:55;-1:-1:-1;3091:20:52;;-1:-1:-1;;;;;3123:30:52;;3120:50;;;3166:1;3163;3156:12;3120:50;3203:4;3195:6;3191:17;3179:29;;3255:3;3248:4;3239:6;3231;3227:19;3223:30;3220:39;3217:59;;;3272:1;3269;3262:12;3217:59;2935:347;;;;;:::o;3287:131::-;-1:-1:-1;;;;;3362:31:52;;3352:42;;3342:70;;3408:1;3405;3398:12;3423:1046;3564:6;3572;3580;3588;3596;3604;3612;3665:3;3653:9;3644:7;3640:23;3636:33;3633:53;;;3682:1;3679;3672:12;3633:53;3705;3750:7;3739:9;3705:53;:::i;:::-;3695:63;;3805:2;3794:9;3790:18;3777:32;3767:42;;3860:3;3849:9;3845:19;3832:33;-1:-1:-1;;;;;3925:2:52;3917:6;3914:14;3911:34;;;3941:1;3938;3931:12;3911:34;3980:58;4030:7;4021:6;4010:9;4006:22;3980:58;:::i;:::-;4057:8;;-1:-1:-1;3954:84:52;-1:-1:-1;4142:3:52;4127:19;;4114:33;;-1:-1:-1;4156:31:52;4114:33;4156:31;:::i;:::-;4206:5;;-1:-1:-1;4264:3:52;4249:19;;4236:33;;4281:16;;;4278:36;;;4310:1;4307;4300:12;4278:36;;4349:60;4401:7;4390:8;4379:9;4375:24;4349:60;:::i;:::-;3423:1046;;;;-1:-1:-1;3423:1046:52;;-1:-1:-1;3423:1046:52;;;;4323:86;;-1:-1:-1;;;3423:1046:52:o;5272:163::-;5339:20;;5399:10;5388:22;;5378:33;;5368:61;;5425:1;5422;5415:12;5368:61;5272:163;;;:::o;5440:252::-;5507:6;5515;5568:2;5556:9;5547:7;5543:23;5539:32;5536:52;;;5584:1;5581;5574:12;5536:52;5607:28;5625:9;5607:28;:::i;:::-;5597:38;5682:2;5667:18;;;;5654:32;;-1:-1:-1;;;5440:252:52:o;5697:118::-;5783:5;5776:13;5769:21;5762:5;5759:32;5749:60;;5805:1;5802;5795:12;5820:489;5914:6;5922;5975:2;5963:9;5954:7;5950:23;5946:32;5943:52;;;5991:1;5988;5981:12;5943:52;6031:9;6018:23;-1:-1:-1;;;;;6056:6:52;6053:30;6050:50;;;6096:1;6093;6086:12;6050:50;6119:69;6180:7;6171:6;6160:9;6156:22;6119:69;:::i;:::-;6109:79;;;6238:2;6227:9;6223:18;6210:32;6251:28;6273:5;6251:28;:::i;:::-;6298:5;6288:15;;;5820:489;;;;;:::o;6314:253::-;616:12;;604:25;;678:4;667:16;;;661:23;645:14;;;638:47;6504:2;6489:18;;6516:45;542:149;6572:159;6639:20;;6699:6;6688:18;;6678:29;;6668:57;;6721:1;6718;6711:12;6736:256;6802:6;6810;6863:2;6851:9;6842:7;6838:23;6834:32;6831:52;;;6879:1;6876;6869:12;6831:52;6902:28;6920:9;6902:28;:::i;:::-;6892:38;;6949:37;6982:2;6971:9;6967:18;6949:37;:::i;:::-;6939:47;;6736:256;;;;;:::o;6997:218::-;7144:2;7133:9;7126:21;7107:4;7164:45;7205:2;7194:9;7190:18;7182:6;7164:45;:::i;7648:247::-;7707:6;7760:2;7748:9;7739:7;7735:23;7731:32;7728:52;;;7776:1;7773;7766:12;7728:52;7815:9;7802:23;7834:31;7859:5;7834:31;:::i;8105:668::-;8217:6;8225;8233;8241;8294:3;8282:9;8273:7;8269:23;8265:33;8262:53;;;8311:1;8308;8301:12;8262:53;8334;8379:7;8368:9;8334:53;:::i;:::-;8324:63;;8438:2;8427:9;8423:18;8410:32;-1:-1:-1;;;;;8457:6:52;8454:30;8451:50;;;8497:1;8494;8487:12;8451:50;8536:58;8586:7;8577:6;8566:9;8562:22;8536:58;:::i;:::-;8613:8;;-1:-1:-1;8510:84:52;-1:-1:-1;;8698:3:52;8683:19;;8670:33;8712:31;8670:33;8712:31;:::i;:::-;8105:668;;;;-1:-1:-1;8105:668:52;;-1:-1:-1;;8105:668:52:o;9149:395::-;9240:8;9250:6;9304:3;9297:4;9289:6;9285:17;9281:27;9271:55;;9322:1;9319;9312:12;9271:55;-1:-1:-1;9345:20:52;;-1:-1:-1;;;;;9377:30:52;;9374:50;;;9420:1;9417;9410:12;9374:50;9457:4;9449:6;9445:17;9433:29;;9517:3;9510:4;9500:6;9497:1;9493:14;9485:6;9481:27;9477:38;9474:47;9471:67;;;9534:1;9531;9524:12;9549:504;9674:6;9682;9735:2;9723:9;9714:7;9710:23;9706:32;9703:52;;;9751:1;9748;9741:12;9703:52;9791:9;9778:23;-1:-1:-1;;;;;9816:6:52;9813:30;9810:50;;;9856:1;9853;9846:12;9810:50;9895:98;9985:7;9976:6;9965:9;9961:22;9895:98;:::i;:::-;10012:8;;9869:124;;-1:-1:-1;9549:504:52;-1:-1:-1;;;;9549:504:52:o;10058:184::-;10116:6;10169:2;10157:9;10148:7;10144:23;10140:32;10137:52;;;10185:1;10182;10175:12;10137:52;10208:28;10226:9;10208:28;:::i;10429:553::-;10515:6;10523;10531;10539;10592:2;10580:9;10571:7;10567:23;10563:32;10560:52;;;10608:1;10605;10598:12;10560:52;10631:28;10649:9;10631:28;:::i;:::-;10621:38;;10678:37;10711:2;10700:9;10696:18;10678:37;:::i;:::-;10668:47;;10766:2;10755:9;10751:18;10738:32;-1:-1:-1;;;;;10785:6:52;10782:30;10779:50;;;10825:1;10822;10815:12;10779:50;10864:58;10914:7;10905:6;10894:9;10890:22;10864:58;:::i;:::-;10429:553;;;;-1:-1:-1;10941:8:52;-1:-1:-1;;;;10429:553:52:o;11490:655::-;11626:6;11634;11642;11686:9;11677:7;11673:23;11716:3;11712:2;11708:12;11705:32;;;11733:1;11730;11723:12;11705:32;11773:9;11760:23;-1:-1:-1;;;;;11798:6:52;11795:30;11792:50;;;11838:1;11835;11828:12;11792:50;11861:69;11922:7;11913:6;11902:9;11898:22;11861:69;:::i;:::-;11851:79;-1:-1:-1;;11964:2:52;-1:-1:-1;;11946:16:52;;11942:25;11939:45;;;11980:1;11977;11970:12;11939:45;;12018:2;12007:9;12003:18;11993:28;;12071:2;12060:9;12056:18;12043:32;12084:31;12109:5;12084:31;:::i;:::-;12134:5;12124:15;;;11490:655;;;;;:::o;12150:609::-;12390:4;12432:3;12421:9;12417:19;12409:27;;12469:6;12463:13;12452:9;12445:32;-1:-1:-1;;;;;12537:4:52;12529:6;12525:17;12519:24;12515:49;12508:4;12497:9;12493:20;12486:79;12612:4;12604:6;12600:17;12594:24;12627:62;12683:4;12672:9;12668:20;12654:12;616;;604:25;;678:4;667:16;;;661:23;645:14;;638:47;542:149;12627:62;-1:-1:-1;616:12:52;;12748:3;12733:19;;604:25;678:4;667:16;;661:23;645:14;;;638:47;12698:55;542:149;12764:234;12847:6;12900:2;12888:9;12879:7;12875:23;12871:32;12868:52;;;12916:1;12913;12906:12;12868:52;12939:53;12984:7;12973:9;12939:53;:::i;13003:127::-;13064:10;13059:3;13055:20;13052:1;13045:31;13095:4;13092:1;13085:15;13119:4;13116:1;13109:15;13403:380;13482:1;13478:12;;;;13525;;;13546:61;;13600:4;13592:6;13588:17;13578:27;;13546:61;13653:2;13645:6;13642:14;13622:18;13619:38;13616:161;;13699:10;13694:3;13690:20;13687:1;13680:31;13734:4;13731:1;13724:15;13762:4;13759:1;13752:15;13788:127;13849:10;13844:3;13840:20;13837:1;13830:31;13880:4;13877:1;13870:15;13904:4;13901:1;13894:15;13920:336;14025:4;14083:11;14070:25;14177:2;14173:7;14162:8;14146:14;14142:29;14138:43;14118:18;14114:68;14104:96;;14196:1;14193;14186:12;14104:96;14217:33;;;;;13920:336;-1:-1:-1;;13920:336:52:o;14261:521::-;14338:4;14344:6;14404:11;14391:25;14498:2;14494:7;14483:8;14467:14;14463:29;14459:43;14439:18;14435:68;14425:96;;14517:1;14514;14507:12;14425:96;14544:33;;14596:20;;;-1:-1:-1;;;;;;14628:30:52;;14625:50;;;14671:1;14668;14661:12;14625:50;14704:4;14692:17;;-1:-1:-1;14735:14:52;14731:27;;;14721:38;;14718:58;;;14772:1;14769;14762:12;14787:184;14845:6;14898:2;14886:9;14877:7;14873:23;14869:32;14866:52;;;14914:1;14911;14904:12;14866:52;14937:28;14955:9;14937:28;:::i;15101:542::-;15202:2;15197:3;15194:11;15191:446;;;15238:1;15262:5;15259:1;15252:16;15306:4;15303:1;15293:18;15376:2;15364:10;15360:19;15357:1;15353:27;15347:4;15343:38;15412:4;15400:10;15397:20;15394:47;;;-1:-1:-1;15435:4:52;15394:47;15490:2;15485:3;15481:12;15478:1;15474:20;15468:4;15464:31;15454:41;;15545:82;15563:2;15556:5;15553:13;15545:82;;;15608:17;;;15589:1;15578:13;15545:82;;15819:1202;-1:-1:-1;;;;;15936:3:52;15933:27;15930:53;;;15963:18;;:::i;:::-;15992:93;16081:3;16041:38;16073:4;16067:11;16041:38;:::i;:::-;16035:4;15992:93;:::i;:::-;16111:1;16136:2;16131:3;16128:11;16153:1;16148:615;;;;16807:1;16824:3;16821:93;;;-1:-1:-1;16880:19:52;;;16867:33;16821:93;-1:-1:-1;;15776:1:52;15772:11;;;15768:24;15764:29;15754:40;15800:1;15796:11;;;15751:57;16927:78;;16121:894;;16148:615;15048:1;15041:14;;;15085:4;15072:18;;-1:-1:-1;;16184:17:52;;;16284:9;16306:229;16320:7;16317:1;16314:14;16306:229;;;16409:19;;;16396:33;16381:49;;16516:4;16501:20;;;;16469:1;16457:14;;;;16336:12;16306:229;;;16310:3;16563;16554:7;16551:16;16548:159;;;16687:1;16683:6;16677:3;16671;16668:1;16664:11;16660:21;16656:34;16652:39;16639:9;16634:3;16630:19;16617:33;16613:79;16605:6;16598:95;16548:159;;;16750:1;16744:3;16741:1;16737:11;16733:19;16727:4;16720:33;16121:894;;15819:1202;;;:::o;17026:266::-;17114:6;17109:3;17102:19;17166:6;17159:5;17152:4;17147:3;17143:14;17130:43;-1:-1:-1;17218:1:52;17193:16;;;17211:4;17189:27;;;17182:38;;;;17274:2;17253:15;;;-1:-1:-1;;17249:29:52;17240:39;;;17236:50;;17026:266::o;17297:1774::-;17554:2;17606:21;;;17579:18;;;17662:22;;;17525:4;;17703:2;17721:18;;;17785:1;17781:14;;;17766:30;;17762:39;;17824:6;17525:4;17858:1184;17872:6;17869:1;17866:13;17858:1184;;;17937:22;;;-1:-1:-1;;17933:36:52;17921:49;;18009:20;;18084:14;18080:27;;;-1:-1:-1;;18076:41:52;18052:66;;18042:94;;18132:1;18129;18122:12;18042:94;18162:31;;18216:4;18278:10;18252:24;18162:31;18252:24;:::i;:::-;18248:41;18240:6;18233:57;18366:6;18331:33;18360:2;18353:5;18349:14;18331:33;:::i;:::-;18327:46;18322:2;18314:6;18310:15;18303:71;18439:2;18432:5;18428:14;18415:28;18528:2;18524:7;18516:5;18500:14;18496:26;18492:40;18470:20;18466:67;18456:95;;18547:1;18544;18537:12;18456:95;18579:32;;;18687:16;;;;-1:-1:-1;18638:21:52;-1:-1:-1;;;;;18719:30:52;;18716:50;;;18762:1;18759;18752:12;18716:50;18815:6;18799:14;18795:27;18786:7;18782:41;18779:61;;;18836:1;18833;18826:12;18779:61;18877:2;18872;18864:6;18860:15;18853:27;18903:59;18958:2;18950:6;18946:15;18938:6;18929:7;18903:59;:::i;:::-;19020:12;;;;18893:69;-1:-1:-1;;;18985:15:52;;;;-1:-1:-1;17894:1:52;17887:9;17858:1184;;;-1:-1:-1;19059:6:52;;17297:1774;-1:-1:-1;;;;;;;;17297:1774:52:o;19076:331::-;19181:9;19192;19234:8;19222:10;19219:24;19216:44;;;19256:1;19253;19246:12;19216:44;19285:6;19275:8;19272:20;19269:40;;;19305:1;19302;19295:12;19269:40;-1:-1:-1;;19331:23:52;;;19376:25;;;;;-1:-1:-1;19076:331:52:o;19412:476::-;19603:3;19641:6;19635:13;19657:66;19716:6;19711:3;19704:4;19696:6;19692:17;19657:66;:::i;:::-;19745:16;;19798:6;19790;19745:16;19770:35;19862:1;19824:18;;19851:13;;;-1:-1:-1;19824:18:52;;19412:476;-1:-1:-1;;;19412:476:52:o;19893:244::-;20050:2;20039:9;20032:21;20013:4;20070:61;20127:2;20116:9;20112:18;20104:6;20096;20070:61;:::i;20142:331::-;20241:4;20299:11;20286:25;20393:3;20389:8;20378;20362:14;20358:29;20354:44;20334:18;20330:69;20320:97;;20413:1;20410;20403:12;20478:129;-1:-1:-1;;;;;20556:5:52;20552:30;20545:5;20542:41;20532:69;;20597:1;20594;20587:12;20612:988;20986:10;20959:25;20977:6;20959:25;:::i;:::-;20955:42;20944:9;20937:61;21061:4;21053:6;21049:17;21036:31;21029:4;21018:9;21014:20;21007:61;20918:4;21115;21107:6;21103:17;21090:31;21130:30;21154:5;21130:30;:::i;:::-;-1:-1:-1;;;;;21202:5:52;21198:30;21191:4;21180:9;21176:20;21169:60;;21265:6;21260:2;21249:9;21245:18;21238:34;21309:3;21303;21292:9;21288:19;21281:32;21336:62;21393:3;21382:9;21378:19;21370:6;21362;21336:62;:::i;:::-;-1:-1:-1;;;;;21435:32:52;;21455:3;21414:19;;21407:61;21505:22;;;21499:3;21484:19;;21477:51;21545:49;21509:6;21579;21571;21545:49;:::i;:::-;21537:57;20612:988;-1:-1:-1;;;;;;;;;;20612:988:52:o;21605:246::-;21672:2;21666:9;;;21702:15;;-1:-1:-1;;;;;21732:34:52;;21768:22;;;21729:62;21726:88;;;21794:18;;:::i;:::-;21830:2;21823:22;21605:246;:::o;21856:896::-;21935:6;21988:2;21976:9;21967:7;21963:23;21959:32;21956:52;;;22004:1;22001;21994:12;21956:52;22037:9;22031:16;-1:-1:-1;;;;;22107:2:52;22099:6;22096:14;22093:34;;;22123:1;22120;22113:12;22093:34;22161:6;22150:9;22146:22;22136:32;;22206:7;22199:4;22195:2;22191:13;22187:27;22177:55;;22228:1;22225;22218:12;22177:55;22257:2;22251:9;22279:2;22275;22272:10;22269:36;;;22285:18;;:::i;:::-;22360:2;22354:9;22328:2;22414:13;;-1:-1:-1;;22410:22:52;;;22434:2;22406:31;22402:40;22390:53;;;22458:18;;;22478:22;;;22455:46;22452:72;;;22504:18;;:::i;:::-;22544:10;22540:2;22533:22;22579:2;22571:6;22564:18;22619:7;22614:2;22609;22605;22601:11;22597:20;22594:33;22591:53;;;22640:1;22637;22630:12;22591:53;22653:68;22718:2;22713;22705:6;22701:15;22696:2;22692;22688:11;22653:68;:::i;22971:341::-;23058:6;23111:2;23099:9;23090:7;23086:23;23082:32;23079:52;;;23127:1;23124;23117:12;23079:52;23153:17;;:::i;:::-;23206:9;23193:23;23186:5;23179:38;23277:2;23266:9;23262:18;23249:32;23244:2;23237:5;23233:14;23226:56;23301:5;23291:15;;;22971:341;;;;:::o;24106:245::-;24164:6;24217:2;24205:9;24196:7;24192:23;24188:32;24185:52;;;24233:1;24230;24223:12;24185:52;24272:9;24259:23;24291:30;24315:5;24291:30;:::i;24356:479::-;24623:1;24619;24614:3;24610:11;24606:19;24598:6;24594:32;24583:9;24576:51;24663:6;24658:2;24647:9;24643:18;24636:34;24718:6;24710;24706:19;24701:2;24690:9;24686:18;24679:47;24762:3;24757:2;24746:9;24742:18;24735:31;24557:4;24783:46;24824:3;24813:9;24809:19;24801:6;24783:46;:::i;:::-;24775:54;24356:479;-1:-1:-1;;;;;;24356:479:52:o;25108:379::-;25301:2;25290:9;25283:21;25264:4;25327:45;25368:2;25357:9;25353:18;25345:6;25327:45;:::i;:::-;25420:9;25412:6;25408:22;25403:2;25392:9;25388:18;25381:50;25448:33;25474:6;25466;25448:33;:::i;25492:245::-;25559:6;25612:2;25600:9;25591:7;25587:23;25583:32;25580:52;;;25628:1;25625;25618:12;25580:52;25660:9;25654:16;25679:28;25701:5;25679:28;:::i;25742:887::-;25961:2;25950:9;25943:21;26019:10;26010:6;26004:13;26000:30;25995:2;25984:9;25980:18;25973:58;26085:4;26077:6;26073:17;26067:24;26062:2;26051:9;26047:18;26040:52;25924:4;26139:2;26131:6;26127:15;26121:22;26180:4;26174:3;26163:9;26159:19;26152:33;26208:52;26255:3;26244:9;26240:19;26226:12;26208:52;:::i;:::-;26194:66;;26309:2;26301:6;26297:15;26291:22;26383:2;26379:7;26367:9;26359:6;26355:22;26351:36;26344:4;26333:9;26329:20;26322:66;26411:41;26445:6;26429:14;26411:41;:::i;:::-;26521:3;26509:16;;;;26503:23;26496:31;26489:39;26483:3;26468:19;;26461:68;-1:-1:-1;;;;;;;;26590:32:52;;;;26583:4;26568:20;;;26561:62;26397:55;25742:887::o;26634:279::-;26704:5;26752:4;26740:9;26735:3;26731:19;26727:30;26724:50;;;26770:1;26767;26760:12;26724:50;26792:17;;:::i;:::-;26783:26;;26838:9;26832:16;26825:5;26818:31;26902:2;26891:9;26887:18;26881:25;26876:2;26869:5;26865:14;26858:49;26634:279;;;;:::o;26918:257::-;27016:6;27069:2;27057:9;27048:7;27044:23;27040:32;27037:52;;;27085:1;27082;27075:12;27037:52;27108:61;27161:7;27150:9;27108:61;:::i;27180:318::-;-1:-1:-1;;;;;;27300:19:52;;27371:11;;;;27402:1;27394:10;;27391:101;;;27479:2;27473;27466:3;27463:1;27459:11;27456:1;27452:19;27448:28;27444:2;27440:37;27436:46;27427:55;;27391:101;;;27180:318;;;;:::o;27782:681::-;27884:6;27937:3;27925:9;27916:7;27912:23;27908:33;27905:53;;;27954:1;27951;27944:12;27905:53;27987:2;27981:9;28029:4;28021:6;28017:17;28100:6;28088:10;28085:22;-1:-1:-1;;;;;28052:10:52;28049:34;28046:62;28043:88;;;28111:18;;:::i;:::-;28147:2;28140:22;28186:16;;28171:32;;28246:2;28231:18;;28225:25;28259:30;28225:25;28259:30;:::i;:::-;28317:2;28305:15;;28298:30;28361:70;28423:7;28418:2;28403:18;;28361:70;:::i;:::-;28356:2;28344:15;;28337:95;28348:6;27782:681;-1:-1:-1;;;27782:681:52:o;28468:217::-;28508:1;28534;28524:132;;28578:10;28573:3;28569:20;28566:1;28559:31;28613:4;28610:1;28603:15;28641:4;28638:1;28631:15;28524:132;-1:-1:-1;28670:9:52;;28468:217::o;28690:265::-;28763:9;;;28794;;28811:15;;;28805:22;;28791:37;28781:168;;28871:10;28866:3;28862:20;28859:1;28852:31;28906:4;28903:1;28896:15;28934:4;28931:1;28924:15;28960:255;29080:19;;29119:2;29111:11;;29108:101;;;-1:-1:-1;;29180:2:52;29176:12;;;29173:1;29169:20;29165:33;29154:45;28960:255;;;;:::o;29220:331::-;-1:-1:-1;;;;;;29340:19:52;;29424:11;;;;29455:1;29447:10;;29444:101;;;29516:1;29512:11;;;;29509:1;29505:19;29501:28;;;29493:37;29489:46;;;;29220:331;-1:-1:-1;;29220:331:52:o;29556:568::-;-1:-1:-1;;;;;29821:3:52;29817:28;29808:6;29803:3;29799:16;29795:51;29790:3;29783:64;29907:10;29902:3;29898:20;29889:6;29884:3;29880:16;29876:43;29872:1;29867:3;29863:11;29856:64;29950:6;29945:2;29940:3;29936:12;29929:28;29765:3;29986:6;29980:13;30002:75;30070:6;30065:2;30060:3;30056:12;30049:4;30041:6;30037:17;30002:75;:::i;:::-;30097:16;;;;30115:2;30093:25;;29556:568;-1:-1:-1;;;;;29556:568:52:o;30424:532::-;30665:6;30660:3;30653:19;-1:-1:-1;;;;;30728:3:52;30724:28;30715:6;30710:3;30706:16;30702:51;30697:2;30692:3;30688:12;30681:73;30784:6;30779:2;30774:3;30770:12;30763:28;30635:3;30820:6;30814:13;30836:73;30902:6;30897:2;30892:3;30888:12;30883:2;30875:6;30871:15;30836:73;:::i;:::-;30929:16;;;;30947:2;30925:25;;30424:532;-1:-1:-1;;;;;30424:532:52:o;30961:251::-;31031:6;31084:2;31072:9;31063:7;31059:23;31055:32;31052:52;;;31100:1;31097;31090:12;31052:52;31132:9;31126:16;31151:31;31176:5;31151:31;:::i
Swarm Source
ipfs://51314fe2191e5e0bf2142fd9e07be7b13940287d713c3af58101b5128772ff1f
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.