Overview
APE Balance
APE Value
$0.00Multichain Info
Latest 25 from a total of 28 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Read | 32467596 | 13 days ago | IN | 6.23629334 APE | 0.08815661 | ||||
| Read | 32467487 | 13 days ago | IN | 0.86537356 APE | 0.0347092 | ||||
| Read | 23282769 | 144 days ago | IN | 0.73368501 APE | 0.01077603 | ||||
| Read | 15919714 | 255 days ago | IN | 2.05000207 APE | 0.02204034 | ||||
| Read | 15913499 | 255 days ago | IN | 0.28251873 APE | 0.00867793 | ||||
| Read | 15913019 | 255 days ago | IN | 0.28251873 APE | 0.00867796 | ||||
| Read | 15912343 | 255 days ago | IN | 0.28251873 APE | 0.00867796 | ||||
| Read | 15901575 | 255 days ago | IN | 0.28251873 APE | 0.00867793 | ||||
| Read | 15018163 | 272 days ago | IN | 1.96989038 APE | 0.01756056 | ||||
| Read | 14981382 | 272 days ago | IN | 0.34884161 APE | 0.00867791 | ||||
| Read | 14974128 | 272 days ago | IN | 0.34884161 APE | 0.00867796 | ||||
| Read | 14973514 | 272 days ago | IN | 0.92097647 APE | 0.01123597 | ||||
| Read | 14972935 | 272 days ago | IN | 0.34884161 APE | 0.00867796 | ||||
| Read | 14937951 | 272 days ago | IN | 0.63490904 APE | 0.00988773 | ||||
| Read | 14771077 | 274 days ago | IN | 0.34884161 APE | 0.00867796 | ||||
| Read | 14770764 | 274 days ago | IN | 0.34884161 APE | 0.00867796 | ||||
| Read | 14770653 | 274 days ago | IN | 0.34884161 APE | 0.00867763 | ||||
| Read | 14770462 | 274 days ago | IN | 0.34884161 APE | 0.00867793 | ||||
| Read | 14749082 | 274 days ago | IN | 0.63490904 APE | 0.00988651 | ||||
| Read | 14748653 | 274 days ago | IN | 0.63490904 APE | 0.00988648 | ||||
| Read | 14747653 | 274 days ago | IN | 0.63490904 APE | 0.00988648 | ||||
| Read | 14746822 | 274 days ago | IN | 0.63490904 APE | 0.00988646 | ||||
| Read | 14744035 | 274 days ago | IN | 0.63490904 APE | 0.00988648 | ||||
| Read | 14679154 | 275 days ago | IN | 0.63490904 APE | 0.00988648 | ||||
| Read | 14477297 | 278 days ago | IN | 1 APE | 0.00929085 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 32467596 | 13 days ago | 6.23629334 APE | ||||
| 32467487 | 13 days ago | 0.86537356 APE | ||||
| 23282769 | 144 days ago | 0.73368501 APE | ||||
| 18481011 | 221 days ago | 0.39674384 APE | ||||
| 18481011 | 221 days ago | 0.39674384 APE | ||||
| 15919714 | 255 days ago | 2.05000207 APE | ||||
| 15913499 | 255 days ago | 0.28251873 APE | ||||
| 15913019 | 255 days ago | 0.28251873 APE | ||||
| 15912343 | 255 days ago | 0.28251873 APE | ||||
| 15901575 | 255 days ago | 0.28251873 APE | ||||
| 15018163 | 272 days ago | 1.96989038 APE | ||||
| 14981382 | 272 days ago | 0.34884161 APE | ||||
| 14974128 | 272 days ago | 0.34884161 APE | ||||
| 14973514 | 272 days ago | 0.92097647 APE | ||||
| 14972935 | 272 days ago | 0.34884161 APE | ||||
| 14937951 | 272 days ago | 0.63490904 APE | ||||
| 14771077 | 274 days ago | 0.34884161 APE | ||||
| 14770764 | 274 days ago | 0.34884161 APE | ||||
| 14770653 | 274 days ago | 0.34884161 APE | ||||
| 14770462 | 274 days ago | 0.34884161 APE | ||||
| 14749082 | 274 days ago | 0.63490904 APE | ||||
| 14748653 | 274 days ago | 0.63490904 APE | ||||
| 14747653 | 274 days ago | 0.63490904 APE | ||||
| 14746822 | 274 days ago | 0.63490904 APE | ||||
| 14744035 | 274 days ago | 0.63490904 APE |
Cross-Chain Transactions
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.29;
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {
ILayerZeroEndpointV2,
MessagingFee,
MessagingReceipt,
Origin
} from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroEndpointV2.sol";
import {
ReadCmdCodecV1,
EVMCallComputeV1,
EVMCallRequestV1
} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/libs/ReadCmdCodecV1.sol";
import {OAppRead} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/OAppRead.sol";
import {OAppOptionsType3} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/libs/OAppOptionsType3.sol";
import {OptionsBuilder} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/libs/OptionsBuilder.sol";
import {AddressCast} from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/AddressCast.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {LibMap} from "solady/src/utils/LibMap.sol";
import {IExclusiveDelegateResolver} from "./interfaces/IExclusiveDelegateResolver.sol";
import {IDelegateRegistry} from "./interfaces/IDelegateRegistry.sol";
import {INFTShadow} from "./interfaces/INFTShadow.sol";
import {IOAppComputerMap} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/interfaces/IOAppComputerMap.sol";
import {IOAppComputerReduce} from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/interfaces/IOAppComputerReduce.sol";
import {SafeCall} from "./utils/SafeCall.sol";
import {CollectionConfig} from "./structs/CollectionConfig.sol";
import {ILayerZeroEndpointLocator} from "./interfaces/ILayerZeroEndpointLocator.sol";
/**
* @notice The Beacon contract is responsible for managing the ownership of NFTs across multiple chains.
* It uses LayerZero's OApp protocol to send messages between chains and maintain ownership records.
*
* @dev This contract is based on the implementation at:
* https://apescan.io/address/0x00000000000087c6dbaDC090d39BC10316f20658
*
* @dev Uses interfaces from the original implementation:
* - IDelegateRegistry (CC0-1.0) by foobar (0xfoobar)
* - IExclusiveDelegateResolver (MIT)
* - ILayerZeroEndpointLocator (MIT)
* - INFTShadow (MIT)
*/
contract Beacon is OAppRead, OAppOptionsType3, IOAppComputerMap, IOAppComputerReduce, AccessControl {
using OptionsBuilder for bytes;
using AddressCast for bytes32;
using AddressCast for address;
using SafeCall for address;
using LibMap for LibMap.Uint32Map;
// The provided contract address is not configured
error ContractNotConfigured();
// The shadow contract has already been deployed
error CollectionAlreadyRegistered();
// The provided endpoint ID matches this contract's eid
error InvalidEid();
// The caller is not the shadow contract
error InvalidCaller();
// The caller is not the contract itself
error OnlyInternalCalls();
// The payload hash does not match the expected hash
error InvalidPayloadHash();
// The beneficiary is the zero address
error BeneficiaryZeroAddress();
// The read channel is under the threshold
error InvalidReadChannel();
// The chain ID is invalid (zero)
error InvalidChain();
// The collection address is zero
error ZeroAddress();
// The array is empty
error ZeroLengthArray();
// The collection address and base collection address do not match
error MismatchedCollectionAddress();
// The maximum gas allocation for lzReceive has been exceeded
error MaxLzReceiveGasAllocationExceeded();
// lzRead returned an invalid state
error InvalidOwner();
// The executor is not allowed
error UnauthorizedExecutor();
// The read request has timed out
error StaleReadRequest();
// The transfer failed
error TransferFailed();
// The burn failed
error BurnFailed();
// The mint failed
error MintFailed();
// The unlock failed
error UnlockFailed();
// The collection is not in shadow mode
error CollectionNotInShadowMode();
// Emitted each time a collection is registered on this Beacon
event Sent(
uint32 indexed eid,
address indexed baseCollectionAddress,
address indexed collection,
uint256[] tokenIds,
address beneficiary
);
// Emitted each time an ownership update is triggered
event ReadTriggered(
address indexed baseCollectionAddress,
address indexed shadowCollectionAddress,
uint32[] eids,
uint256[] tokenIds
);
// Emitted once for each collection registered on this Beacon
event CollectionRegistered(
address indexed collectionAddress, address indexed baseCollectionAddress, uint32 indexed baseCollectionEid
);
// Emitted when a message fails and ends up in the cache
event MessageCached(uint32 indexed srcEid, bytes32 indexed sender, uint64 nonce, bytes reason);
// Emitted when a cached message is executed
event CachedMessageExecuted(uint32 indexed srcEid, bytes32 indexed sender, uint64 nonce);
// Emitted when the execution enforcement is set
event EnforceExecutionSet(bool enforceExecutors);
// Emitted when an executor is allowed or disallowed
event AllowedExecutorSet(address executor, bool allowed);
// Emitted when the required confirmations for an EID are set
event RequiredConfirmationsSet(uint32 eid, uint16 confirmations);
// Emitted when the read channel is set
event ReadChannelSet(uint32 readChannel);
// Constants for SafeCall
uint256 private constant _SAFE_CALL_BUFFER = 50_000;
// costs used for generating LZRead options
uint128 private constant _DELEGATION_UPDATE_COST = 203_911; // worst case cost of delegateERC721
uint128 private constant _BASE_OWNERSHIP_UPDATE_COST = 60_000; // worst case cost of transferFrom
uint128 private constant _INCREMENTAL_OWNERSHIP_UPDATE_COST = 50_000; // incremental cost of transferFrom
uint32 private constant _BASE_READ_RETURN_DATA_SIZE = 224; // 32 bytes for collection address, 64 bytes for each array
uint32 private constant _READ_SIZE_INCREMENT_PER_UPDATE = 96; // One element in each of three arrays (staleOwner, newOwner, tokenId)
uint32 private constant _EXT_CALL_GAS = 2_600;
uint256 private constant _READ_TIMEOUT = 30 minutes;
// Limit the gas allocation for lzReceive to prevent DOS issues
uint128 private constant _LZ_RECEIVE_MAX_GAS_ALLOCATION = 8_000_000;
// The role for the collection registrar
bytes32 public constant COLLECTION_REGISTRAR_ROLE = keccak256("COLLECTION_REGISTRAR_ROLE");
// The necessary delegate rights for the shadow token
bytes32 private constant _GLOBAL_RIGHTS_WITH_MAX_EXPIRY = bytes32(uint256(type(uint40).max));
bytes24 public immutable SHADOW_TOKEN_RIGHTS;
// The endpoint ID of this contract
uint32 public immutable THIS_CONTRACT_EID;
// The address of the exclusive delegate resolver
address public immutable EXCLUSIVE_DELEGATE_RESOLVER_ADDRESS;
// the address of the delegate registry
address public immutable DELEGATE_REGISTRY_ADDRESS;
// The read channel ID
uint32 public readChannel;
// Single mapping for all collection configuration
mapping(address baseCollectionAddress => CollectionConfig) public collectionConfigs;
mapping(address shadowCollectionAddress => address baseCollectionAddress) private _shadowToBase;
// Tracks delegated ownership for native collections
mapping(address collection => mapping(uint256 tokenId => address delegatedOwner)) public delegatedOwners;
// Store the hash of messages that failed to execute
mapping(uint32 => mapping(bytes32 => mapping(uint64 => bytes32))) public payloadHashes;
// Mapping of allowed executors, enforced if enforceExecutors is true
mapping(address executor => bool allowed) public allowedExecutors;
// Mapping of init timestamps for each read request
mapping(bytes32 guid => uint256 timestamp) public initTimestamps;
// Enforce executors if true
bool public enforceExecutors;
// LZ static variables
uint8 private constant _MAP_AND_REDUCE = 2;
uint16 private constant _MSG_TYPE = 1;
uint32 private constant _READ_CHANNEL_EID_THRESHOLD = 4294965694;
// Mapping of required confirmations per EID
LibMap.Uint32Map private _requiredConfirmations;
/**
* @notice Initializes the Beacon contract.
* @param _endpointLocator The address of the LayerZero endpoint locator.
* @param _delegate The address allowed to set LZ configuration for this contract.
* @param _readChannel The ID of the read channel.
* @param _delegatexyz The address of the delegate registry.
* @param _exclusiveDelegateResolver The address of the exclusive delegate resolver.
*/
constructor(
address _endpointLocator,
address _delegate,
uint32 _readChannel,
address _delegatexyz,
address _exclusiveDelegateResolver,
address _initialAdmin
) OAppRead(ILayerZeroEndpointLocator(_endpointLocator).endpoint(), _delegate) Ownable(_initialAdmin) {
if (_readChannel <= _READ_CHANNEL_EID_THRESHOLD) revert InvalidReadChannel();
EXCLUSIVE_DELEGATE_RESOLVER_ADDRESS = _exclusiveDelegateResolver;
DELEGATE_REGISTRY_ADDRESS = _delegatexyz;
SHADOW_TOKEN_RIGHTS = bytes24(keccak256(abi.encode(block.chainid)));
THIS_CONTRACT_EID = ILayerZeroEndpointV2(ILayerZeroEndpointLocator(_endpointLocator).endpoint()).eid();
readChannel = _readChannel;
_grantRole(COLLECTION_REGISTRAR_ROLE, _initialAdmin);
_grantRole(DEFAULT_ADMIN_ROLE, _initialAdmin);
_setPeer(readChannel, address(this).toBytes32());
}
/**
* @notice Register a collection (either native or shadow).
* @param shadowCollectionAddress The address of the collection to register.
* @param baseCollectionChainId The chain ID of the base collection.
* @param baseCollectionAddress The address of the base collection.
* @param baseCollectionEid The endpoint ID of the base collection.
* @param baseCollectionPerNftOwnershipUpdateCost The cost of updating the ownership of an NFT. Set to 0 to use Beacon's default.
* @dev If the collection is native:
* - baseCollectionChainId must match block.chainid
* - baseCollectionEid must match THIS_CONTRACT_EID
* - baseCollectionAddress must match shadowCollectionAddress
*/
function registerCollection(
address shadowCollectionAddress,
uint32 baseCollectionChainId,
address baseCollectionAddress,
uint32 baseCollectionEid,
uint32 baseCollectionPerNftOwnershipUpdateCost
) external onlyRole(COLLECTION_REGISTRAR_ROLE) {
_validateCollectionConfiguration(
shadowCollectionAddress,
baseCollectionAddress,
baseCollectionChainId,
baseCollectionEid,
baseCollectionPerNftOwnershipUpdateCost
);
_shadowToBase[shadowCollectionAddress] = baseCollectionAddress;
collectionConfigs[baseCollectionAddress] = CollectionConfig({
baseCollectionChainId: baseCollectionChainId,
baseCollectionEid: baseCollectionEid,
shadowAddress: shadowCollectionAddress,
baseCollectionPerNftOwnershipUpdateCost: baseCollectionPerNftOwnershipUpdateCost
});
emit CollectionRegistered(shadowCollectionAddress, baseCollectionAddress, baseCollectionEid);
}
/**
* @notice Trigger an ownership update for a collection.
* @param baseCollectionAddress The address on this chain of the collection to update.
* @param eids The array of endpoint IDs to try reading ownership from. At max, one will return a valid response.
* @param tokenIds The array of token IDs to update ownership for.
* @param refundRecipient The address to refund the excess LZ fee to, if any exists.
* @param supplementalGasLimit The gas limit for the callback.
*/
function read(
address baseCollectionAddress,
uint256[] calldata tokenIds,
uint32[] calldata eids,
address refundRecipient,
uint128 supplementalGasLimit
) external payable returns (bytes32) {
if (tokenIds.length == 0 || eids.length == 0) revert ZeroLengthArray();
CollectionConfig storage config = collectionConfigs[baseCollectionAddress];
address shadowCollectionAddress = config.shadowAddress;
if (shadowCollectionAddress == address(0)) revert ContractNotConfigured();
if (!_collectionIsNative(config) && !INFTShadow(shadowCollectionAddress).shadowModeEnabled()) {
revert CollectionNotInShadowMode();
}
bytes memory cmd = _buildCmd(baseCollectionAddress, eids, tokenIds);
bytes memory options = this.combineOptions(
readChannel, _MSG_TYPE, getReadOptions(baseCollectionAddress, tokenIds, supplementalGasLimit)
);
MessagingReceipt memory receipt = _lzSend(
readChannel, cmd, options, MessagingFee({nativeFee: msg.value, lzTokenFee: 0}), payable(refundRecipient)
);
bytes32 guid = receipt.guid;
initTimestamps[guid] = block.timestamp;
emit ReadTriggered(baseCollectionAddress, shadowCollectionAddress, eids, tokenIds);
return guid;
}
/**
* @notice Releases tokens on a specific eid.
* @param dstEid The endpoint ID to release the tokens on.
* @param baseCollectionAddress The address of the base collection to release the tokens for.
* @param tokenIds The array of token IDs to release.
* @param beneficiary The address to receive the tokens.
* @param refundRecipient The address to refund the excess LZ fee to, if any exists.
* @notice should be triggered by the shadow contract, calls from EOAs for contracts that are not configured will revert
*/
function send(
uint32 dstEid,
address baseCollectionAddress,
uint256[] calldata tokenIds,
address beneficiary,
address refundRecipient,
uint128 supplementalGasLimit
) external payable {
if (beneficiary == address(0)) revert BeneficiaryZeroAddress();
if (dstEid == THIS_CONTRACT_EID || dstEid > _READ_CHANNEL_EID_THRESHOLD) revert InvalidEid();
if (tokenIds.length == 0) revert ZeroLengthArray();
CollectionConfig storage config = collectionConfigs[baseCollectionAddress];
address shadowCollectionAddress = config.shadowAddress;
bool isNative = _collectionIsNative(config);
if (isNative) {
for (uint256 i = 0; i < tokenIds.length; i++) {
uint256 tokenId = tokenIds[i];
// if the collection is native, the caller must be the owner (enforced by transferring from msg.sender)
IERC721(shadowCollectionAddress).transferFrom(msg.sender, address(this), tokenId);
}
} else {
// if the collection is not native, the Shadow must be the caller (Shadow should enforce that the caller is approved or the owner)
if (msg.sender != shadowCollectionAddress) revert InvalidCaller();
}
bytes memory payload = abi.encode(baseCollectionAddress, beneficiary, tokenIds);
bytes memory options = this.combineOptions(
dstEid, _MSG_TYPE, getSendOptions(dstEid, baseCollectionAddress, tokenIds, supplementalGasLimit)
);
_lzSend(dstEid, payload, options, MessagingFee({nativeFee: msg.value, lzTokenFee: 0}), payable(refundRecipient));
emit Sent(dstEid, baseCollectionAddress, shadowCollectionAddress, tokenIds, beneficiary);
}
function executeMessage(Origin calldata _origin, bytes32 guid, bytes calldata _message) external {
if (msg.sender != address(this)) revert OnlyInternalCalls();
_executeMessage(_origin, guid, _message);
}
/**
* @notice Set whether to enforce executors.
* @param _enforceExecutors Whether to enforce executors.
*/
function setEnforceExecutors(bool _enforceExecutors) external onlyOwner {
enforceExecutors = _enforceExecutors;
emit EnforceExecutionSet(_enforceExecutors);
}
/**
* @notice Set whether an executor is allowed.
* @param executor The address of the executor.
* @param allowed Whether the executor is allowed.
*/
function setAllowedExecutor(address executor, bool allowed) external onlyOwner {
allowedExecutors[executor] = allowed;
emit AllowedExecutorSet(executor, allowed);
}
/**
* @notice Set the required confirmations for a read request on an EID.
* @param eid The endpoint ID to set the required confirmations for.
* @param confirmations The required confirmations.
*/
function setRequiredConfirmations(uint32 eid, uint16 confirmations) external onlyOwner {
_requiredConfirmations.set(eid, confirmations);
emit RequiredConfirmationsSet(eid, confirmations);
}
/**
* @notice sets the base collection per nft ownership update cost
* @param baseCollectionAddress The address of the base collection.
* @param cost The cost of updating the ownership of an NFT.
*/
function setBaseCollectionPerNftOwnershipUpdateCost(address baseCollectionAddress, uint32 cost)
external
onlyOwner
{
collectionConfigs[baseCollectionAddress].baseCollectionPerNftOwnershipUpdateCost = cost;
}
/**
* @notice Set the read channel for the Beacon.
* @param _readChannel The new read channel.
*/
function setReadChannel(uint32 _readChannel) external onlyOwner {
if (_readChannel <= _READ_CHANNEL_EID_THRESHOLD) revert InvalidReadChannel();
readChannel = _readChannel;
emit ReadChannelSet(_readChannel);
}
/**
* @notice Get the required confirmations for a read request on an EID.
* @param eid The endpoint ID to get the required confirmations for.
* @return uint32 The required confirmations.
*/
function requiredConfirmations(uint32 eid) external view returns (uint16) {
return uint16(_requiredConfirmations.get(eid));
}
/**
* @notice Get the base collection address for a given shadow collection address.
* @param shadowCollectionAddress The address of the shadow collection.
* @return address the base collection address.
*/
function shadowToBase(address shadowCollectionAddress) external view returns (address) {
return _shadowToBase[shadowCollectionAddress];
}
/**
* @notice Get the shadow collection address for a given base collection address.
* @param baseCollectionAddress The address of the base collection.
* @return address the shadow collection address.
*/
function baseToShadow(address baseCollectionAddress) external view returns (address) {
return collectionConfigs[baseCollectionAddress].shadowAddress;
}
/**
* @notice Calculate fees for sending a read request for an array of token IDs.
* @param baseCollectionAddress The address of the collection to calculate fees for.
* @param tokenIds The array of token IDs to calculate fees for.
* @param dstEids The array of endpoint IDs to calculate fees for.
* @param supplementalGasLimit The gas limit for the callback.
* @return nativeFee The native fee for the message.
* @return lzTokenFee The LZ token fee for the message.
* @dev the shadow contract has a variant with built in options to simplify.
*/
function quoteRead(
address baseCollectionAddress,
uint256[] calldata tokenIds,
uint32[] calldata dstEids,
uint128 supplementalGasLimit
) external view returns (uint256 nativeFee, uint256 lzTokenFee) {
CollectionConfig storage config = collectionConfigs[baseCollectionAddress];
address shadowCollectionAddress = config.shadowAddress;
if (shadowCollectionAddress == address(0)) revert ContractNotConfigured();
bytes memory cmd = _buildCmd(shadowCollectionAddress, dstEids, tokenIds);
bytes memory options = this.combineOptions(
readChannel, _MSG_TYPE, getReadOptions(baseCollectionAddress, tokenIds, supplementalGasLimit)
);
MessagingFee memory fee = _quote(readChannel, cmd, options, false);
return (fee.nativeFee, fee.lzTokenFee);
}
/**
* @notice Calculate fees for sending a message to the shadow contract.
* @param dstEid The endpoint ID to send the message to.
* @param baseCollectionAddress The address of the collection to calculate fees for.
* @param tokenIds The array of token IDs to calculate fees for.
* @return nativeFee The native fee for the message.
* @return lzTokenFee The LZ token fee for the message.
* @dev the shadow contract has a variant with built in options to simplify.
*/
function quoteSend(
uint32 dstEid,
address baseCollectionAddress,
uint256[] calldata tokenIds,
uint128 supplementalGasLimit
) external view returns (uint256 nativeFee, uint256 lzTokenFee) {
CollectionConfig storage config = collectionConfigs[baseCollectionAddress];
address shadowCollectionAddress = config.shadowAddress;
if (shadowCollectionAddress == address(0)) revert ContractNotConfigured();
bytes memory payload = abi.encode(baseCollectionAddress, address(0), tokenIds);
bytes memory options = this.combineOptions(
dstEid, _MSG_TYPE, getSendOptions(dstEid, baseCollectionAddress, tokenIds, supplementalGasLimit)
);
MessagingFee memory fee = _quote(dstEid, payload, options, false);
return (fee.nativeFee, fee.lzTokenFee);
}
/**
* @notice Fetch the owner of a token from the delegate resolver.
* @param baseCollectionAddress The address of the collection to fetch the owner for.
* @param tokenId The ID of the token to fetch the owner for.
* @return _owner the owner of the token.
* @return _isLocked true if the token is locked, false otherwise.
* @dev reverts if the contract is not configured or the token is locked.
*/
function unlockedExclusiveOwnerByRights(address baseCollectionAddress, uint256 tokenId, bytes24 rightsIdentifier)
external
view
returns (address _owner, bool _isLocked)
{
CollectionConfig memory config = collectionConfigs[baseCollectionAddress];
if (config.baseCollectionEid == 0) return (address(0), true);
bool isNative = config.baseCollectionChainId == block.chainid;
address shadowCollectionAddress = config.shadowAddress;
address _baseOwner;
if (isNative) {
try IERC721(shadowCollectionAddress).ownerOf(tokenId) returns (address owner) {
if (owner == address(this)) {
return (address(this), true);
} else {
_baseOwner = owner;
}
} catch {
// if the token does not exist in a native collection, we can preemptively return address(0) as the owner
return (address(0), false);
}
} else {
// if collection is not configured or the token is locked, return _isLocked = true to render it a no-op
if (shadowCollectionAddress == address(0) || INFTShadow(shadowCollectionAddress).locked(tokenId)) {
return (address(0), true);
} else {
try INFTShadow(shadowCollectionAddress).ownerOf(tokenId) returns (address owner) {
_baseOwner = owner;
} catch {
// if the token does not exist for an unlocked shadow, the token was burned
_baseOwner = address(0);
}
}
}
// otherwise, we return the exclusive owner by rights according to the delegate resolver
try IExclusiveDelegateResolver(EXCLUSIVE_DELEGATE_RESOLVER_ADDRESS).exclusiveOwnerByRights(
shadowCollectionAddress, tokenId, rightsIdentifier
) returns (address owner) {
return (owner, false);
} catch {
return (_baseOwner, false);
}
}
/**
* @notice Processes individual NFT ownership responses for consumption by lzReduce.
* @param _request The original read request data.
* @param _response The response from the ownership query (encoded address, bool)
* @return bytes memory encoded (staleOwner, newOwner, tokenId)
*/
function lzMap(bytes calldata _request, bytes calldata _response) external view override returns (bytes memory) {
(address collectionAddress, uint256 tokenId) = abi.decode(_request[46:110], (address, uint256));
address staleOwner;
(address newOwner, bool isLocked) = abi.decode(_response, (address, bool));
if (isLocked) return new bytes(0);
CollectionConfig memory config = collectionConfigs[collectionAddress];
if (_collectionIsNative(config)) {
// For native collections, read from delegation mapping
staleOwner = delegatedOwners[collectionAddress][tokenId];
} else {
// For shadow collections, read from the shadow contract
try INFTShadow(config.shadowAddress).ownerOf(tokenId) returns (address owner) {
staleOwner = owner;
} catch {
// ownerOf reverts if the token does not exist
staleOwner = address(0);
}
}
return abi.encode(staleOwner, newOwner, tokenId);
}
/**
* @notice Reduces the response from the ownership query post lzMap
* @param _responses An array of abi encoded (staleOwner, newOwner, tokenId)
* @return bytes memory encoded (collectionAddress, staleOwners, newOwners, tokenIds)
*/
function lzReduce(bytes calldata _request, bytes[] calldata _responses)
external
view
override
returns (bytes memory)
{
address collectionAddress = address(bytes20(_request[64:84]));
CollectionConfig memory config = collectionConfigs[collectionAddress];
address targetAddress = config.shadowAddress;
address[] memory staleOwners = new address[](_responses.length);
address[] memory newOwners = new address[](_responses.length);
uint256[] memory tokenIds = new uint256[](_responses.length);
uint256 updateCount = 0;
for (uint256 i = 0; i < _responses.length; i++) {
if (_responses[i].length == 0) {
// lzMap returns empty bytes if ownership data is not available
continue;
}
(staleOwners[i], newOwners[i], tokenIds[i]) = abi.decode(_responses[i], (address, address, uint256));
if (staleOwners[i] != newOwners[i]) {
tokenIds[updateCount] = tokenIds[i];
staleOwners[updateCount] = staleOwners[i];
newOwners[updateCount] = newOwners[i];
unchecked {
++updateCount;
}
}
}
// if updateCount is less than the length of the tokenIds array, we need to resize the arrays
if (updateCount < tokenIds.length) {
address[] memory resizedStaleOwners = new address[](updateCount);
address[] memory resizedNewOwners = new address[](updateCount);
uint256[] memory resizedTokenIds = new uint256[](updateCount);
for (uint256 i = 0; i < updateCount; i++) {
resizedStaleOwners[i] = staleOwners[i];
resizedNewOwners[i] = newOwners[i];
resizedTokenIds[i] = tokenIds[i];
}
return abi.encode(targetAddress, resizedStaleOwners, resizedNewOwners, resizedTokenIds);
}
return abi.encode(targetAddress, staleOwners, newOwners, tokenIds);
}
/**
* @notice Generates options for a send operation.
* @param dstEid The endpoint ID to send the message to.
* @param baseCollectionAddress The address of the base collection.
* @param tokenIds The array of token IDs.
* @param supplementalGasLimit The gas limit for the send operation.
* @return options The options bytes.
*/
function getSendOptions(
uint32 dstEid,
address baseCollectionAddress,
uint256[] calldata tokenIds,
uint128 supplementalGasLimit
) public view returns (bytes memory) {
CollectionConfig memory config = collectionConfigs[baseCollectionAddress];
bool targetIsNative = config.baseCollectionEid == dstEid;
uint128 totalGasRequired = _calculateLzReceiveGasAllocation(
config.baseCollectionPerNftOwnershipUpdateCost, supplementalGasLimit, tokenIds.length, targetIsNative, false
);
return OptionsBuilder.newOptions().addExecutorLzReceiveOption(totalGasRequired, 0);
}
/**
* @notice Generates options for a read operation.
* @param baseCollectionAddress The address of the base collection.
* @param tokenIds The array of token IDs.
* @return options The options bytes.
*/
function getReadOptions(address baseCollectionAddress, uint256[] calldata tokenIds, uint128 supplementalGasLimit)
public
view
returns (bytes memory)
{
CollectionConfig memory config = collectionConfigs[baseCollectionAddress];
bool isNative = config.baseCollectionChainId == block.chainid;
uint128 totalGasRequired = _calculateLzReceiveGasAllocation(
config.baseCollectionPerNftOwnershipUpdateCost, supplementalGasLimit, tokenIds.length, isNative, true
);
uint32 totalReturnDataSize =
_BASE_READ_RETURN_DATA_SIZE + (_READ_SIZE_INCREMENT_PER_UPDATE * uint32(tokenIds.length));
bytes memory options =
OptionsBuilder.newOptions().addExecutorLzReadOption(totalGasRequired, totalReturnDataSize, 0);
return options;
}
/**
* @notice Handle incoming messages from LayerZero.
* @dev the message type is determined by the srcEid.
* @dev read responses will update the ownership of the tokens.
* @dev traditional LZ messages will update the lock state of the tokens.
*/
function _lzReceive(
Origin calldata _origin,
bytes32 guid,
bytes calldata _message,
address executor,
bytes calldata /* _extraData */
) internal override {
if (enforceExecutors && !allowedExecutors[executor]) revert UnauthorizedExecutor();
// Prepare the execution calldata
bytes memory callData = abi.encodeWithSelector(this.executeMessage.selector, _origin, guid, _message);
// Calculate gas to forward, leaving some in reserve
uint256 externalGas = gasleft() - _SAFE_CALL_BUFFER;
// Use SafeCall to execute with gas limit and capture return data
(bool success, bytes memory reason) = address(this).safeCall(externalGas, 0, 4, callData);
if (!success) {
// Cache failed message hash
bytes32 payloadHash = keccak256(abi.encodePacked(address(this), callData, block.chainid));
payloadHashes[_origin.srcEid][_origin.sender][_origin.nonce] = payloadHash;
emit MessageCached(_origin.srcEid, _origin.sender, _origin.nonce, reason);
}
}
/**
* @notice Retry a failed message.
* @param srcEid The source endpoint ID.
* @param sender The sender of the message.
* @param nonce The nonce of the message.
* @param origin The original origin of the message.
* @param message The message to retry.
* @dev only allow retries for EIDs under the read channel threshold
* @dev the consequence for failed reads is low enough that we can just retry
*/
function retryFailedMessage(
uint32 srcEid,
bytes32 sender,
uint64 nonce,
Origin calldata origin,
bytes32 guid,
bytes calldata message
) external {
// only allow retries for EIDs under the read channel threshold
if (srcEid > _READ_CHANNEL_EID_THRESHOLD) revert InvalidEid();
// Prepare calldata and verify hash
bytes memory callData = abi.encodeWithSelector(this.executeMessage.selector, origin, guid, message);
bytes32 payloadHash = keccak256(abi.encodePacked(address(this), callData, block.chainid));
if (payloadHashes[srcEid][sender][nonce] != payloadHash) revert InvalidPayloadHash();
// Clear cache before execution
delete payloadHashes[srcEid][sender][nonce];
// Execute with SafeCall, using all remaining gas
// limit return data to 4 bytes, it will either be a custom error with no data, or nothing
(bool success, bytes memory reason) = address(this).safeCall(gasleft(), 0, 4, callData);
if (!success) {
// If retry fails, revert with the reason
assembly {
revert(add(32, reason), mload(reason))
}
}
emit CachedMessageExecuted(srcEid, sender, nonce);
}
function _executeMessage(Origin calldata _origin, bytes32 guid, bytes calldata _message) internal {
if (_origin.srcEid > _READ_CHANNEL_EID_THRESHOLD) {
if (block.timestamp - initTimestamps[guid] > _READ_TIMEOUT) revert StaleReadRequest();
// Handle lzRead responses
_updateOwnership(_message, guid);
} else {
// Handle standard LayerZero messages.
_updateLockState(_message);
}
}
function _updateOwnership(bytes calldata _message, bytes32 guid) internal {
(address shadowAddress, address[] memory staleOwners, address[] memory newOwners, uint256[] memory tokenIds) =
abi.decode(_message, (address, address[], address[], uint256[]));
address baseCollectionAddress = _shadowToBase[shadowAddress];
CollectionConfig memory config = collectionConfigs[baseCollectionAddress];
bool isNative = _collectionIsNative(config);
// For shadow collections, use the shadow contract
INFTShadow _shadow = INFTShadow(shadowAddress);
if (isNative) {
// For native collections, update the delegated ownership
_updateDelegations(baseCollectionAddress, newOwners, tokenIds);
} else {
for (uint256 i = 0; i < tokenIds.length; i++) {
address staleOwner = staleOwners[i];
address newOwner = newOwners[i];
uint256 tokenId = tokenIds[i];
if (staleOwner == address(0)) {
(bool success,) =
address(_shadow).call(abi.encodeWithSignature("mint(address,uint256)", newOwner, tokenId));
if (!success) revert MintFailed();
} else if (newOwner == address(0)) {
(bool success,) = address(_shadow).call(abi.encodeWithSignature("burn(uint256)", tokenId));
if (!success) revert BurnFailed();
} else {
(bool success,) = address(_shadow).call(
abi.encodeWithSignature("transferFrom(address,address,uint256)", staleOwner, newOwner, tokenId)
);
if (!success) revert TransferFailed();
}
}
_shadow.executeCallback(guid);
}
}
function _updateLockState(bytes calldata _message) internal {
(address collectionAddress, address beneficiary, uint256[] memory tokenIds) =
abi.decode(_message, (address, address, uint256[]));
CollectionConfig storage config = collectionConfigs[collectionAddress];
if (config.shadowAddress == address(0)) revert ContractNotConfigured();
bool isNative = config.baseCollectionChainId == block.chainid;
if (isNative) {
// Handle standard LayerZero messages.
_clearDelegationsAndReleaseTokens(collectionAddress, beneficiary, tokenIds);
} else {
// For shadow collections, unlock tokens in the shadow contract
(bool success,) = address(INFTShadow(config.shadowAddress)).call(
abi.encodeWithSignature("unlockTokens(uint256[],address)", tokenIds, beneficiary)
);
if (!success) revert UnlockFailed();
}
}
/**
* @notice Build the command for a read request.
* @param targetCollectionAddress The address on the target chain to read from.
* @param eids The array of endpoint IDs to build the command for.
* @param tokenIds The array of token IDs to build the command for.
* @return bytes memory The built command.
*/
function _buildCmd(address targetCollectionAddress, uint32[] calldata eids, uint256[] calldata tokenIds)
internal
view
returns (bytes memory)
{
// Construct the call to the beacon on peer eid to fetch ownership from that eid's exclusive delegate resolver
EVMCallRequestV1[] memory readRequests = new EVMCallRequestV1[](tokenIds.length * eids.length);
for (uint256 i = 0; i < tokenIds.length; i++) {
for (uint256 j = 0; j < eids.length; j++) {
uint32 confirmations = _requiredConfirmations.get(eids[j]);
if (confirmations == 0) revert InvalidEid();
readRequests[i * eids.length + j] = EVMCallRequestV1({
appRequestLabel: uint16(i + 1 + j * tokenIds.length),
targetEid: eids[j],
isBlockNum: false,
blockNumOrTimestamp: uint64(block.timestamp),
confirmations: uint16(confirmations),
to: _getPeerOrRevert(eids[j]).toAddress(),
callData: abi.encodeWithSelector(
this.unlockedExclusiveOwnerByRights.selector,
targetCollectionAddress,
tokenIds[i],
SHADOW_TOKEN_RIGHTS
)
});
}
}
EVMCallComputeV1 memory computeSettings =
EVMCallComputeV1(_MAP_AND_REDUCE, THIS_CONTRACT_EID, false, uint64(block.timestamp), 0, address(this));
return ReadCmdCodecV1.encode(0, readRequests, computeSettings);
}
/**
* @notice Updates the delegations based on the received message.
* @param collectionAddress The address of the collection.
* @param newOwners The array of new owners.
* @param tokenIds The array of token IDs.
*/
function _updateDelegations(address collectionAddress, address[] memory newOwners, uint256[] memory tokenIds)
internal
{
bytes[] memory multicallRawData = new bytes[](tokenIds.length * 2);
uint256 multicallDataLength = 0;
address nftContractToDelegate = collectionAddress;
for (uint256 i = 0; i < tokenIds.length; ++i) {
address newOwner = newOwners[i];
uint256 tokenId = tokenIds[i];
address staleOwner = delegatedOwners[collectionAddress][tokenId];
if (IERC721(collectionAddress).ownerOf(tokenId) != address(this)) {
revert InvalidOwner();
}
if (staleOwner != address(0)) {
multicallRawData[multicallDataLength] = abi.encodeWithSelector(
IDelegateRegistry.delegateERC721.selector,
staleOwner,
nftContractToDelegate,
tokenId,
_GLOBAL_RIGHTS_WITH_MAX_EXPIRY,
false
);
unchecked {
++multicallDataLength;
}
}
if (newOwner != address(0)) {
multicallRawData[multicallDataLength] = abi.encodeWithSelector(
IDelegateRegistry.delegateERC721.selector,
newOwner,
nftContractToDelegate,
tokenId,
_GLOBAL_RIGHTS_WITH_MAX_EXPIRY,
true
);
unchecked {
++multicallDataLength;
}
delegatedOwners[collectionAddress][tokenId] = newOwner;
}
}
bytes[] memory multicallData = new bytes[](multicallDataLength);
for (uint256 i = 0; i < multicallDataLength; ++i) {
multicallData[i] = multicallRawData[i];
}
if (multicallDataLength > 0) {
IDelegateRegistry(DELEGATE_REGISTRY_ADDRESS).multicall(multicallData);
}
}
/**
* @notice Clears the delegations and releases the tokens.
* @param collectionAddress The address of the collection.
* @param beneficiary The address of the beneficiary.
* @param tokenIds The array of token IDs.
*/
function _clearDelegationsAndReleaseTokens(
address collectionAddress,
address beneficiary,
uint256[] memory tokenIds
) internal {
for (uint256 i = 0; i < tokenIds.length; ++i) {
IERC721(collectionAddress).transferFrom(address(this), beneficiary, tokenIds[i]);
}
_clearDelegations(collectionAddress, tokenIds);
}
/**
* @notice Clears the delegations.
* @param collectionAddress The address of the collection.
* @param tokenIds The array of token IDs.
*/
function _clearDelegations(address collectionAddress, uint256[] memory tokenIds) internal {
bytes[] memory multicallDataRaw = new bytes[](tokenIds.length);
address nftContractToDelegate = collectionAddress;
uint256 multicallDataLength = 0;
for (uint256 i = 0; i < tokenIds.length; ++i) {
uint256 tokenId = tokenIds[i];
address delegatedOwner = delegatedOwners[collectionAddress][tokenId];
if (delegatedOwner == address(0)) continue;
multicallDataRaw[i] = abi.encodeWithSelector(
IDelegateRegistry.delegateERC721.selector,
delegatedOwner,
nftContractToDelegate,
tokenId,
_GLOBAL_RIGHTS_WITH_MAX_EXPIRY,
false
);
unchecked {
++multicallDataLength;
}
delegatedOwners[collectionAddress][tokenId] = address(0);
}
bytes[] memory multicallData = new bytes[](multicallDataLength);
for (uint256 i = 0; i < multicallDataLength; ++i) {
multicallData[i] = multicallDataRaw[i];
}
if (multicallDataLength > 0) {
IDelegateRegistry(DELEGATE_REGISTRY_ADDRESS).multicall(multicallData);
}
}
function _collectionIsNative(CollectionConfig memory config) internal view returns (bool) {
if (config.baseCollectionChainId == 0) revert ContractNotConfigured();
return config.baseCollectionChainId == block.chainid;
}
function _validateCollectionConfiguration(
address shadowCollectionAddress,
address baseCollectionAddress,
uint256 baseCollectionChainId,
uint32 baseCollectionEid,
uint128 baseCollectionPerNftOwnershipUpdateCost
) internal view {
if (baseCollectionChainId == 0) revert InvalidChain();
if (baseCollectionEid == 0) revert InvalidEid();
if (baseCollectionAddress == address(0)) revert ZeroAddress();
if (shadowCollectionAddress == address(0)) revert ZeroAddress();
if (baseCollectionPerNftOwnershipUpdateCost > _LZ_RECEIVE_MAX_GAS_ALLOCATION) {
revert MaxLzReceiveGasAllocationExceeded();
}
bool isNative = baseCollectionChainId == block.chainid;
if (isNative) {
if (baseCollectionEid != THIS_CONTRACT_EID) revert InvalidEid();
if (shadowCollectionAddress != baseCollectionAddress) revert MismatchedCollectionAddress();
} else {
if (baseCollectionEid == THIS_CONTRACT_EID) revert InvalidEid();
}
if (collectionConfigs[baseCollectionAddress].shadowAddress != address(0)) revert CollectionAlreadyRegistered();
}
function _calculateLzReceiveGasAllocation(
uint128 baseCollectionPerNftOwnershipUpdateCost,
uint128 supplementalGasLimit,
uint256 tokenIdsLength,
bool isNative,
bool isRead
) internal pure returns (uint128 totalGasRequired) {
if (isRead) {
unchecked {
uint128 baseUpdateCost = isNative
? uint128(_SAFE_CALL_BUFFER + _BASE_OWNERSHIP_UPDATE_COST)
: _EXT_CALL_GAS + uint128(_SAFE_CALL_BUFFER + _BASE_OWNERSHIP_UPDATE_COST);
uint128 incrementalUpdateCost =
isNative ? _DELEGATION_UPDATE_COST * 2 : _INCREMENTAL_OWNERSHIP_UPDATE_COST;
totalGasRequired = baseUpdateCost + incrementalUpdateCost * uint128(tokenIdsLength);
}
} else {
unchecked {
uint128 nftOwnershipUpdateCost = isNative && baseCollectionPerNftOwnershipUpdateCost != 0
? baseCollectionPerNftOwnershipUpdateCost
: _INCREMENTAL_OWNERSHIP_UPDATE_COST;
uint128 perNftCost =
isNative ? nftOwnershipUpdateCost + _DELEGATION_UPDATE_COST : nftOwnershipUpdateCost;
totalGasRequired =
uint128(_SAFE_CALL_BUFFER + _BASE_OWNERSHIP_UPDATE_COST + perNftCost * tokenIdsLength);
}
}
totalGasRequired += supplementalGasLimit;
if (totalGasRequired > _LZ_RECEIVE_MAX_GAS_ALLOCATION) revert MaxLzReceiveGasAllocationExceeded();
}
}// SPDX-License-Identifier: LZBL-1.2
pragma solidity ^0.8.20;
import "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/CalldataBytesLib.sol";
library ExecutorOptions {
using CalldataBytesLib for bytes;
uint8 internal constant WORKER_ID = 1;
uint8 internal constant OPTION_TYPE_LZRECEIVE = 1;
uint8 internal constant OPTION_TYPE_NATIVE_DROP = 2;
uint8 internal constant OPTION_TYPE_LZCOMPOSE = 3;
uint8 internal constant OPTION_TYPE_ORDERED_EXECUTION = 4;
uint8 internal constant OPTION_TYPE_LZREAD = 5;
error Executor_InvalidLzReceiveOption();
error Executor_InvalidNativeDropOption();
error Executor_InvalidLzComposeOption();
error Executor_InvalidLzReadOption();
/// @dev decode the next executor option from the options starting from the specified cursor
/// @param _options [executor_id][executor_option][executor_id][executor_option]...
/// executor_option = [option_size][option_type][option]
/// option_size = len(option_type) + len(option)
/// executor_id: uint8, option_size: uint16, option_type: uint8, option: bytes
/// @param _cursor the cursor to start decoding from
/// @return optionType the type of the option
/// @return option the option of the executor
/// @return cursor the cursor to start decoding the next executor option
function nextExecutorOption(
bytes calldata _options,
uint256 _cursor
) internal pure returns (uint8 optionType, bytes calldata option, uint256 cursor) {
unchecked {
// skip worker id
cursor = _cursor + 1;
// read option size
uint16 size = _options.toU16(cursor);
cursor += 2;
// read option type
optionType = _options.toU8(cursor);
// startCursor and endCursor are used to slice the option from _options
uint256 startCursor = cursor + 1; // skip option type
uint256 endCursor = cursor + size;
option = _options[startCursor:endCursor];
cursor += size;
}
}
function decodeLzReceiveOption(bytes calldata _option) internal pure returns (uint128 gas, uint128 value) {
if (_option.length != 16 && _option.length != 32) revert Executor_InvalidLzReceiveOption();
gas = _option.toU128(0);
value = _option.length == 32 ? _option.toU128(16) : 0;
}
function decodeNativeDropOption(bytes calldata _option) internal pure returns (uint128 amount, bytes32 receiver) {
if (_option.length != 48) revert Executor_InvalidNativeDropOption();
amount = _option.toU128(0);
receiver = _option.toB32(16);
}
function decodeLzComposeOption(
bytes calldata _option
) internal pure returns (uint16 index, uint128 gas, uint128 value) {
if (_option.length != 18 && _option.length != 34) revert Executor_InvalidLzComposeOption();
index = _option.toU16(0);
gas = _option.toU128(2);
value = _option.length == 34 ? _option.toU128(18) : 0;
}
function decodeLzReadOption(
bytes calldata _option
) internal pure returns (uint128 gas, uint32 calldataSize, uint128 value) {
if (_option.length != 20 && _option.length != 36) revert Executor_InvalidLzReadOption();
gas = _option.toU128(0);
calldataSize = _option.toU32(16);
value = _option.length == 36 ? _option.toU128(20) : 0;
}
function encodeLzReceiveOption(uint128 _gas, uint128 _value) internal pure returns (bytes memory) {
return _value == 0 ? abi.encodePacked(_gas) : abi.encodePacked(_gas, _value);
}
function encodeNativeDropOption(uint128 _amount, bytes32 _receiver) internal pure returns (bytes memory) {
return abi.encodePacked(_amount, _receiver);
}
function encodeLzComposeOption(uint16 _index, uint128 _gas, uint128 _value) internal pure returns (bytes memory) {
return _value == 0 ? abi.encodePacked(_index, _gas) : abi.encodePacked(_index, _gas, _value);
}
function encodeLzReadOption(
uint128 _gas,
uint32 _calldataSize,
uint128 _value
) internal pure returns (bytes memory) {
return _value == 0 ? abi.encodePacked(_gas, _calldataSize) : abi.encodePacked(_gas, _calldataSize, _value);
}
}// SPDX-License-Identifier: LZBL-1.2
pragma solidity ^0.8.20;
import { BytesLib } from "solidity-bytes-utils/contracts/BytesLib.sol";
import { BitMap256 } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/BitMaps.sol";
import { CalldataBytesLib } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/CalldataBytesLib.sol";
library DVNOptions {
using CalldataBytesLib for bytes;
using BytesLib for bytes;
uint8 internal constant WORKER_ID = 2;
uint8 internal constant OPTION_TYPE_PRECRIME = 1;
error DVN_InvalidDVNIdx();
error DVN_InvalidDVNOptions(uint256 cursor);
/// @dev group dvn options by its idx
/// @param _options [dvn_id][dvn_option][dvn_id][dvn_option]...
/// dvn_option = [option_size][dvn_idx][option_type][option]
/// option_size = len(dvn_idx) + len(option_type) + len(option)
/// dvn_id: uint8, dvn_idx: uint8, option_size: uint16, option_type: uint8, option: bytes
/// @return dvnOptions the grouped options, still share the same format of _options
/// @return dvnIndices the dvn indices
function groupDVNOptionsByIdx(
bytes memory _options
) internal pure returns (bytes[] memory dvnOptions, uint8[] memory dvnIndices) {
if (_options.length == 0) return (dvnOptions, dvnIndices);
uint8 numDVNs = getNumDVNs(_options);
// if there is only 1 dvn, we can just return the whole options
if (numDVNs == 1) {
dvnOptions = new bytes[](1);
dvnOptions[0] = _options;
dvnIndices = new uint8[](1);
dvnIndices[0] = _options.toUint8(3); // dvn idx
return (dvnOptions, dvnIndices);
}
// otherwise, we need to group the options by dvn_idx
dvnIndices = new uint8[](numDVNs);
dvnOptions = new bytes[](numDVNs);
unchecked {
uint256 cursor = 0;
uint256 start = 0;
uint8 lastDVNIdx = 255; // 255 is an invalid dvn_idx
while (cursor < _options.length) {
++cursor; // skip worker_id
// optionLength asserted in getNumDVNs (skip check)
uint16 optionLength = _options.toUint16(cursor);
cursor += 2;
// dvnIdx asserted in getNumDVNs (skip check)
uint8 dvnIdx = _options.toUint8(cursor);
// dvnIdx must equal to the lastDVNIdx for the first option
// so it is always skipped in the first option
// this operation slices out options whenever the scan finds a different lastDVNIdx
if (lastDVNIdx == 255) {
lastDVNIdx = dvnIdx;
} else if (dvnIdx != lastDVNIdx) {
uint256 len = cursor - start - 3; // 3 is for worker_id and option_length
bytes memory opt = _options.slice(start, len);
_insertDVNOptions(dvnOptions, dvnIndices, lastDVNIdx, opt);
// reset the start and lastDVNIdx
start += len;
lastDVNIdx = dvnIdx;
}
cursor += optionLength;
}
// skip check the cursor here because the cursor is asserted in getNumDVNs
// if we have reached the end of the options, we need to process the last dvn
uint256 size = cursor - start;
bytes memory op = _options.slice(start, size);
_insertDVNOptions(dvnOptions, dvnIndices, lastDVNIdx, op);
// revert dvnIndices to start from 0
for (uint8 i = 0; i < numDVNs; ++i) {
--dvnIndices[i];
}
}
}
function _insertDVNOptions(
bytes[] memory _dvnOptions,
uint8[] memory _dvnIndices,
uint8 _dvnIdx,
bytes memory _newOptions
) internal pure {
// dvnIdx starts from 0 but default value of dvnIndices is 0,
// so we tell if the slot is empty by adding 1 to dvnIdx
if (_dvnIdx == 255) revert DVN_InvalidDVNIdx();
uint8 dvnIdxAdj = _dvnIdx + 1;
for (uint256 j = 0; j < _dvnIndices.length; ++j) {
uint8 index = _dvnIndices[j];
if (dvnIdxAdj == index) {
_dvnOptions[j] = abi.encodePacked(_dvnOptions[j], _newOptions);
break;
} else if (index == 0) {
// empty slot, that means it is the first time we see this dvn
_dvnIndices[j] = dvnIdxAdj;
_dvnOptions[j] = _newOptions;
break;
}
}
}
/// @dev get the number of unique dvns
/// @param _options the format is the same as groupDVNOptionsByIdx
function getNumDVNs(bytes memory _options) internal pure returns (uint8 numDVNs) {
uint256 cursor = 0;
BitMap256 bitmap;
// find number of unique dvn_idx
unchecked {
while (cursor < _options.length) {
++cursor; // skip worker_id
uint16 optionLength = _options.toUint16(cursor);
cursor += 2;
if (optionLength < 2) revert DVN_InvalidDVNOptions(cursor); // at least 1 byte for dvn_idx and 1 byte for option_type
uint8 dvnIdx = _options.toUint8(cursor);
// if dvnIdx is not set, increment numDVNs
// max num of dvns is 255, 255 is an invalid dvn_idx
// The order of the dvnIdx is not required to be sequential, as enforcing the order may weaken
// the composability of the options. e.g. if we refrain from enforcing the order, an OApp that has
// already enforced certain options can append additional options to the end of the enforced
// ones without restrictions.
if (dvnIdx == 255) revert DVN_InvalidDVNIdx();
if (!bitmap.get(dvnIdx)) {
++numDVNs;
bitmap = bitmap.set(dvnIdx);
}
cursor += optionLength;
}
}
if (cursor != _options.length) revert DVN_InvalidDVNOptions(cursor);
}
/// @dev decode the next dvn option from _options starting from the specified cursor
/// @param _options the format is the same as groupDVNOptionsByIdx
/// @param _cursor the cursor to start decoding
/// @return optionType the type of the option
/// @return option the option
/// @return cursor the cursor to start decoding the next option
function nextDVNOption(
bytes calldata _options,
uint256 _cursor
) internal pure returns (uint8 optionType, bytes calldata option, uint256 cursor) {
unchecked {
// skip worker id
cursor = _cursor + 1;
// read option size
uint16 size = _options.toU16(cursor);
cursor += 2;
// read option type
optionType = _options.toU8(cursor + 1); // skip dvn_idx
// startCursor and endCursor are used to slice the option from _options
uint256 startCursor = cursor + 2; // skip option type and dvn_idx
uint256 endCursor = cursor + size;
option = _options[startCursor:endCursor];
cursor += size;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IOAppComputerMap {
function lzMap(bytes calldata _request, bytes calldata _response) external view returns (bytes memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IOAppComputerReduce {
function lzReduce(bytes calldata _cmd, bytes[] calldata _responses) external view returns (bytes memory);
}// 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;
/**
* @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 { IOAppOptionsType3, EnforcedOptionParam } from "../interfaces/IOAppOptionsType3.sol";
/**
* @title OAppOptionsType3
* @dev Abstract contract implementing the IOAppOptionsType3 interface with type 3 options.
*/
abstract contract OAppOptionsType3 is IOAppOptionsType3, Ownable {
uint16 internal constant OPTION_TYPE_3 = 3;
// @dev The "msgType" should be defined in the child contract.
mapping(uint32 eid => mapping(uint16 msgType => bytes enforcedOption)) public enforcedOptions;
/**
* @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 {
_setEnforcedOptions(_enforcedOptions);
}
/**
* @dev Sets the enforced options for specific endpoint and message type combinations.
* @param _enforcedOptions An array of EnforcedOptionParam structures specifying enforced options.
*
* @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[] memory _enforcedOptions) internal virtual {
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) {
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 memory _options) internal pure virtual {
uint16 optionsType;
assembly {
optionsType := mload(add(_options, 2))
}
if (optionsType != OPTION_TYPE_3) revert InvalidOptions(_options);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { BytesLib } from "solidity-bytes-utils/contracts/BytesLib.sol";
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { ExecutorOptions } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/libs/ExecutorOptions.sol";
import { DVNOptions } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/libs/DVNOptions.sol";
/**
* @title OptionsBuilder
* @dev Library for building and encoding various message options.
*/
library OptionsBuilder {
using SafeCast for uint256;
using BytesLib for bytes;
// Constants for options types
uint16 internal constant TYPE_1 = 1; // legacy options type 1
uint16 internal constant TYPE_2 = 2; // legacy options type 2
uint16 internal constant TYPE_3 = 3;
// Custom error message
error InvalidSize(uint256 max, uint256 actual);
error InvalidOptionType(uint16 optionType);
// Modifier to ensure only options of type 3 are used
modifier onlyType3(bytes memory _options) {
if (_options.toUint16(0) != TYPE_3) revert InvalidOptionType(_options.toUint16(0));
_;
}
/**
* @dev Creates a new options container with type 3.
* @return options The newly created options container.
*/
function newOptions() internal pure returns (bytes memory) {
return abi.encodePacked(TYPE_3);
}
/**
* @dev Adds an executor LZ receive option to the existing options.
* @param _options The existing options container.
* @param _gas The gasLimit used on the lzReceive() function in the OApp.
* @param _value The msg.value passed to the lzReceive() function in the OApp.
* @return options The updated options container.
*
* @dev When multiples of this option are added, they are summed by the executor
* eg. if (_gas: 200k, and _value: 1 ether) AND (_gas: 100k, _value: 0.5 ether) are sent in an option to the LayerZeroEndpoint,
* that becomes (300k, 1.5 ether) when the message is executed on the remote lzReceive() function.
*/
function addExecutorLzReceiveOption(
bytes memory _options,
uint128 _gas,
uint128 _value
) internal pure onlyType3(_options) returns (bytes memory) {
bytes memory option = ExecutorOptions.encodeLzReceiveOption(_gas, _value);
return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_LZRECEIVE, option);
}
/**
* @dev Adds an executor LZ read option to the existing options.
* @param _options The existing options container.
* @param _gas The gas limit used for the lzReceive() function in the ReadOApp.
* @param _calldataSize The size of the payload for lzReceive() function in the ReadOApp.
* @param _value The msg.value passed to the lzReceive() function in the ReadOApp.
* @return options The updated options container.
*/
function addExecutorLzReadOption(
bytes memory _options,
uint128 _gas,
uint32 _calldataSize,
uint128 _value
) internal pure onlyType3(_options) returns (bytes memory) {
bytes memory option = ExecutorOptions.encodeLzReadOption(_gas, _calldataSize, _value);
return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_LZREAD, option);
}
/**
* @dev Adds an executor native drop option to the existing options.
* @param _options The existing options container.
* @param _amount The amount for the native value that is airdropped to the 'receiver'.
* @param _receiver The receiver address for the native drop option.
* @return options The updated options container.
*
* @dev When multiples of this option are added, they are summed by the executor on the remote chain.
*/
function addExecutorNativeDropOption(
bytes memory _options,
uint128 _amount,
bytes32 _receiver
) internal pure onlyType3(_options) returns (bytes memory) {
bytes memory option = ExecutorOptions.encodeNativeDropOption(_amount, _receiver);
return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_NATIVE_DROP, option);
}
/**
* @dev Adds an executor LZ compose option to the existing options.
* @param _options The existing options container.
* @param _index The index for the lzCompose() function call.
* @param _gas The gasLimit for the lzCompose() function call.
* @param _value The msg.value for the lzCompose() function call.
* @return options The updated options container.
*
* @dev When multiples of this option are added, they are summed PER index by the executor on the remote chain.
* @dev If the OApp sends N lzCompose calls on the remote, you must provide N incremented indexes starting with 0.
* ie. When your remote OApp composes (N = 3) messages, you must set this option for index 0,1,2
*/
function addExecutorLzComposeOption(
bytes memory _options,
uint16 _index,
uint128 _gas,
uint128 _value
) internal pure onlyType3(_options) returns (bytes memory) {
bytes memory option = ExecutorOptions.encodeLzComposeOption(_index, _gas, _value);
return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_LZCOMPOSE, option);
}
/**
* @dev Adds an executor ordered execution option to the existing options.
* @param _options The existing options container.
* @return options The updated options container.
*/
function addExecutorOrderedExecutionOption(
bytes memory _options
) internal pure onlyType3(_options) returns (bytes memory) {
return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_ORDERED_EXECUTION, bytes(""));
}
/**
* @dev Adds a DVN pre-crime option to the existing options.
* @param _options The existing options container.
* @param _dvnIdx The DVN index for the pre-crime option.
* @return options The updated options container.
*/
function addDVNPreCrimeOption(
bytes memory _options,
uint8 _dvnIdx
) internal pure onlyType3(_options) returns (bytes memory) {
return addDVNOption(_options, _dvnIdx, DVNOptions.OPTION_TYPE_PRECRIME, bytes(""));
}
/**
* @dev Adds an executor option to the existing options.
* @param _options The existing options container.
* @param _optionType The type of the executor option.
* @param _option The encoded data for the executor option.
* @return options The updated options container.
*/
function addExecutorOption(
bytes memory _options,
uint8 _optionType,
bytes memory _option
) internal pure onlyType3(_options) returns (bytes memory) {
return
abi.encodePacked(
_options,
ExecutorOptions.WORKER_ID,
_option.length.toUint16() + 1, // +1 for optionType
_optionType,
_option
);
}
/**
* @dev Adds a DVN option to the existing options.
* @param _options The existing options container.
* @param _dvnIdx The DVN index for the DVN option.
* @param _optionType The type of the DVN option.
* @param _option The encoded data for the DVN option.
* @return options The updated options container.
*/
function addDVNOption(
bytes memory _options,
uint8 _dvnIdx,
uint8 _optionType,
bytes memory _option
) internal pure onlyType3(_options) returns (bytes memory) {
return
abi.encodePacked(
_options,
DVNOptions.WORKER_ID,
_option.length.toUint16() + 2, // +2 for optionType and dvnIdx
_dvnIdx,
_optionType,
_option
);
}
/**
* @dev Encodes legacy options of type 1.
* @param _executionGas The gasLimit value passed to lzReceive().
* @return legacyOptions The encoded legacy options.
*/
function encodeLegacyOptionsType1(uint256 _executionGas) internal pure returns (bytes memory) {
if (_executionGas > type(uint128).max) revert InvalidSize(type(uint128).max, _executionGas);
return abi.encodePacked(TYPE_1, _executionGas);
}
/**
* @dev Encodes legacy options of type 2.
* @param _executionGas The gasLimit value passed to lzReceive().
* @param _nativeForDst The amount of native air dropped to the receiver.
* @param _receiver The _nativeForDst receiver address.
* @return legacyOptions The encoded legacy options of type 2.
*/
function encodeLegacyOptionsType2(
uint256 _executionGas,
uint256 _nativeForDst,
bytes memory _receiver // @dev Use bytes instead of bytes32 in legacy type 2 for _receiver.
) internal pure returns (bytes memory) {
if (_executionGas > type(uint128).max) revert InvalidSize(type(uint128).max, _executionGas);
if (_nativeForDst > type(uint128).max) revert InvalidSize(type(uint128).max, _nativeForDst);
if (_receiver.length > 32) revert InvalidSize(32, _receiver.length);
return abi.encodePacked(TYPE_2, _executionGas, _nativeForDst, _receiver);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
struct EVMCallRequestV1 {
uint16 appRequestLabel; // Label identifying the application or type of request (can be use in lzCompute)
uint32 targetEid; // Target endpoint ID (representing a target blockchain)
bool isBlockNum; // True if the request = block number, false if timestamp
uint64 blockNumOrTimestamp; // Block number or timestamp to use in the request
uint16 confirmations; // Number of block confirmations on top of the requested block number or timestamp before the view function can be called
address to; // Address of the target contract on the target chain
bytes callData; // Calldata for the contract call
}
struct EVMCallComputeV1 {
uint8 computeSetting; // Compute setting (0 = map only, 1 = reduce only, 2 = map reduce)
uint32 targetEid; // Target endpoint ID (representing a target blockchain)
bool isBlockNum; // True if the request = block number, false if timestamp
uint64 blockNumOrTimestamp; // Block number or timestamp to use in the request
uint16 confirmations; // Number of block confirmations on top of the requested block number or timestamp before the view function can be called
address to; // Address of the target contract on the target chain
}
library ReadCmdCodecV1 {
using SafeCast for uint256;
uint16 internal constant CMD_VERSION = 1;
uint8 internal constant REQUEST_VERSION = 1;
uint16 internal constant RESOLVER_TYPE_SINGLE_VIEW_EVM_CALL = 1;
uint8 internal constant COMPUTE_VERSION = 1;
uint16 internal constant COMPUTE_TYPE_SINGLE_VIEW_EVM_CALL = 1;
error InvalidVersion();
error InvalidType();
function decode(
bytes calldata _cmd
)
internal
pure
returns (uint16 appCmdLabel, EVMCallRequestV1[] memory evmCallRequests, EVMCallComputeV1 memory compute)
{
uint256 offset = 0;
uint16 cmdVersion = uint16(bytes2(_cmd[offset:offset + 2]));
offset += 2;
if (cmdVersion != CMD_VERSION) revert InvalidVersion();
appCmdLabel = uint16(bytes2(_cmd[offset:offset + 2]));
offset += 2;
(evmCallRequests, offset) = decodeRequestsV1(_cmd, offset);
// decode the compute if it exists
if (offset < _cmd.length) {
(compute, ) = decodeEVMCallComputeV1(_cmd, offset);
}
}
function decodeRequestsV1(
bytes calldata _cmd,
uint256 _offset
) internal pure returns (EVMCallRequestV1[] memory evmCallRequests, uint256 newOffset) {
newOffset = _offset;
uint16 requestCount = uint16(bytes2(_cmd[newOffset:newOffset + 2]));
newOffset += 2;
evmCallRequests = new EVMCallRequestV1[](requestCount);
for (uint16 i = 0; i < requestCount; i++) {
uint8 requestVersion = uint8(_cmd[newOffset]);
newOffset += 1;
if (requestVersion != REQUEST_VERSION) revert InvalidVersion();
uint16 appRequestLabel = uint16(bytes2(_cmd[newOffset:newOffset + 2]));
newOffset += 2;
uint16 resolverType = uint16(bytes2(_cmd[newOffset:newOffset + 2]));
newOffset += 2;
if (resolverType == RESOLVER_TYPE_SINGLE_VIEW_EVM_CALL) {
(EVMCallRequestV1 memory request, uint256 nextOffset) = decodeEVMCallRequestV1(
_cmd,
newOffset,
appRequestLabel
);
newOffset = nextOffset;
evmCallRequests[i] = request;
} else {
revert InvalidType();
}
}
}
function decodeEVMCallRequestV1(
bytes calldata _cmd,
uint256 _offset,
uint16 _appRequestLabel
) internal pure returns (EVMCallRequestV1 memory request, uint256 newOffset) {
newOffset = _offset;
request.appRequestLabel = _appRequestLabel;
uint16 requestSize = uint16(bytes2(_cmd[newOffset:newOffset + 2]));
newOffset += 2;
request.targetEid = uint32(bytes4(_cmd[newOffset:newOffset + 4]));
newOffset += 4;
request.isBlockNum = uint8(_cmd[newOffset]) == 1;
newOffset += 1;
request.blockNumOrTimestamp = uint64(bytes8(_cmd[newOffset:newOffset + 8]));
newOffset += 8;
request.confirmations = uint16(bytes2(_cmd[newOffset:newOffset + 2]));
newOffset += 2;
request.to = address(bytes20(_cmd[newOffset:newOffset + 20]));
newOffset += 20;
uint16 callDataSize = requestSize - 35;
request.callData = _cmd[newOffset:newOffset + callDataSize];
newOffset += callDataSize;
}
function decodeEVMCallComputeV1(
bytes calldata _cmd,
uint256 _offset
) internal pure returns (EVMCallComputeV1 memory compute, uint256 newOffset) {
newOffset = _offset;
uint8 computeVersion = uint8(_cmd[newOffset]);
newOffset += 1;
if (computeVersion != COMPUTE_VERSION) revert InvalidVersion();
uint16 computeType = uint16(bytes2(_cmd[newOffset:newOffset + 2]));
newOffset += 2;
if (computeType != COMPUTE_TYPE_SINGLE_VIEW_EVM_CALL) revert InvalidType();
compute.computeSetting = uint8(_cmd[newOffset]);
newOffset += 1;
compute.targetEid = uint32(bytes4(_cmd[newOffset:newOffset + 4]));
newOffset += 4;
compute.isBlockNum = uint8(_cmd[newOffset]) == 1;
newOffset += 1;
compute.blockNumOrTimestamp = uint64(bytes8(_cmd[newOffset:newOffset + 8]));
newOffset += 8;
compute.confirmations = uint16(bytes2(_cmd[newOffset:newOffset + 2]));
newOffset += 2;
compute.to = address(bytes20(_cmd[newOffset:newOffset + 20]));
newOffset += 20;
}
function decodeCmdAppLabel(bytes calldata _cmd) internal pure returns (uint16) {
uint256 offset = 0;
uint16 cmdVersion = uint16(bytes2(_cmd[offset:offset + 2]));
offset += 2;
if (cmdVersion != CMD_VERSION) revert InvalidVersion();
return uint16(bytes2(_cmd[offset:offset + 2]));
}
function decodeRequestV1AppRequestLabel(bytes calldata _request) internal pure returns (uint16) {
uint256 offset = 0;
uint8 requestVersion = uint8(_request[offset]);
offset += 1;
if (requestVersion != REQUEST_VERSION) revert InvalidVersion();
return uint16(bytes2(_request[offset:offset + 2]));
}
function encode(
uint16 _appCmdLabel,
EVMCallRequestV1[] memory _evmCallRequests,
EVMCallComputeV1 memory _evmCallCompute
) internal pure returns (bytes memory) {
bytes memory cmd = encode(_appCmdLabel, _evmCallRequests);
if (_evmCallCompute.targetEid != 0) {
// if eid is 0, it means no compute
cmd = appendEVMCallComputeV1(cmd, _evmCallCompute);
}
return cmd;
}
function encode(
uint16 _appCmdLabel,
EVMCallRequestV1[] memory _evmCallRequests
) internal pure returns (bytes memory) {
bytes memory cmd = abi.encodePacked(CMD_VERSION, _appCmdLabel, _evmCallRequests.length.toUint16());
for (uint256 i = 0; i < _evmCallRequests.length; i++) {
cmd = appendEVMCallRequestV1(cmd, _evmCallRequests[i]);
}
return cmd;
}
// todo: optimize this with Buffer
function appendEVMCallRequestV1(
bytes memory _cmd,
EVMCallRequestV1 memory _request
) internal pure returns (bytes memory) {
bytes memory newCmd = abi.encodePacked(
_cmd,
REQUEST_VERSION,
_request.appRequestLabel,
RESOLVER_TYPE_SINGLE_VIEW_EVM_CALL,
(_request.callData.length + 35).toUint16(),
_request.targetEid
);
return
abi.encodePacked(
newCmd,
_request.isBlockNum,
_request.blockNumOrTimestamp,
_request.confirmations,
_request.to,
_request.callData
);
}
function appendEVMCallComputeV1(
bytes memory _cmd,
EVMCallComputeV1 memory _compute
) internal pure returns (bytes memory) {
return
abi.encodePacked(
_cmd,
COMPUTE_VERSION,
COMPUTE_TYPE_SINGLE_VIEW_EVM_CALL,
_compute.computeSetting,
_compute.targetEid,
_compute.isBlockNum,
_compute.blockNumOrTimestamp,
_compute.confirmations,
_compute.to
);
}
}// 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 { OAppSender, MessagingFee, MessagingReceipt } from "./OAppSender.sol";
// @dev Import the 'Origin' so it's exposed to OApp implementers
// solhint-disable-next-line no-unused-import
import { OAppReceiver, Origin } from "./OAppReceiver.sol";
import { OAppCore } from "./OAppCore.sol";
/**
* @title OApp
* @dev Abstract contract serving as the base for OApp implementation, combining OAppSender and OAppReceiver functionality.
*/
abstract contract OApp is OAppSender, OAppReceiver {
/**
* @dev Constructor to initialize the OApp with the provided endpoint and owner.
* @param _endpoint The address of the LOCAL LayerZero endpoint.
* @param _delegate The delegate capable of making OApp configurations inside of the endpoint.
*/
constructor(address _endpoint, address _delegate) OAppCore(_endpoint, _delegate) {}
/**
* @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(OAppSender, OAppReceiver)
returns (uint64 senderVersion, uint64 receiverVersion)
{
return (SENDER_VERSION, RECEIVER_VERSION);
}
}// 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 { AddressCast } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/AddressCast.sol";
import { OApp } from "./OApp.sol";
abstract contract OAppRead is OApp {
constructor(address _endpoint, address _delegate) OApp(_endpoint, _delegate) {}
// -------------------------------
// Only Owner
function setReadChannel(uint32 _channelId, bool _active) public virtual onlyOwner {
_setPeer(_channelId, _active ? AddressCast.toBytes32(address(this)) : bytes32(0));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { IOAppReceiver, Origin } from "./interfaces/IOAppReceiver.sol";
import { OAppCore } from "./OAppCore.sol";
/**
* @title OAppReceiver
* @dev Abstract contract implementing the ILayerZeroReceiver interface and extending OAppCore for OApp receivers.
*/
abstract contract OAppReceiver is IOAppReceiver, OAppCore {
// 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;
/**
* @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 { 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.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;
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: 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;
library CalldataBytesLib {
function toU8(bytes calldata _bytes, uint256 _start) internal pure returns (uint8) {
return uint8(_bytes[_start]);
}
function toU16(bytes calldata _bytes, uint256 _start) internal pure returns (uint16) {
unchecked {
uint256 end = _start + 2;
return uint16(bytes2(_bytes[_start:end]));
}
}
function toU32(bytes calldata _bytes, uint256 _start) internal pure returns (uint32) {
unchecked {
uint256 end = _start + 4;
return uint32(bytes4(_bytes[_start:end]));
}
}
function toU64(bytes calldata _bytes, uint256 _start) internal pure returns (uint64) {
unchecked {
uint256 end = _start + 8;
return uint64(bytes8(_bytes[_start:end]));
}
}
function toU128(bytes calldata _bytes, uint256 _start) internal pure returns (uint128) {
unchecked {
uint256 end = _start + 16;
return uint128(bytes16(_bytes[_start:end]));
}
}
function toU256(bytes calldata _bytes, uint256 _start) internal pure returns (uint256) {
unchecked {
uint256 end = _start + 32;
return uint256(bytes32(_bytes[_start:end]));
}
}
function toAddr(bytes calldata _bytes, uint256 _start) internal pure returns (address) {
unchecked {
uint256 end = _start + 20;
return address(bytes20(_bytes[_start:end]));
}
}
function toB32(bytes calldata _bytes, uint256 _start) internal pure returns (bytes32) {
unchecked {
uint256 end = _start + 32;
return bytes32(_bytes[_start:end]);
}
}
}// SPDX-License-Identifier: MIT
// modified from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/structs/BitMaps.sol
pragma solidity ^0.8.20;
type BitMap256 is uint256;
using BitMaps for BitMap256 global;
library BitMaps {
/**
* @dev Returns whether the bit at `index` is set.
*/
function get(BitMap256 bitmap, uint8 index) internal pure returns (bool) {
uint256 mask = 1 << index;
return BitMap256.unwrap(bitmap) & mask != 0;
}
/**
* @dev Sets the bit at `index`.
*/
function set(BitMap256 bitmap, uint8 index) internal pure returns (BitMap256) {
uint256 mask = 1 << index;
return BitMap256.wrap(BitMap256.unwrap(bitmap) | mask);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` from `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC-165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted to signal this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
* Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}// 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/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.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.3.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 Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(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.1.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC-721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC-721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
* {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
* a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// 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/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// 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
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
/**
* @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
*/
function toUint(bool b) internal pure returns (uint256 u) {
assembly ("memory-safe") {
u := iszero(iszero(b))
}
}
}// SPDX-License-Identifier: CC0-1.0
pragma solidity >=0.8.13;
/**
* @title IDelegateRegistry
* @custom:version 2.0
* @custom:author foobar (0xfoobar)
* @notice A standalone immutable registry storing delegated permissions from one address to another
*/
interface IDelegateRegistry {
/// @notice Delegation type, NONE is used when a delegation does not exist or is revoked
enum DelegationType {
NONE,
ALL,
CONTRACT,
ERC721,
ERC20,
ERC1155
}
/// @notice Struct for returning delegations
struct Delegation {
DelegationType type_;
address to;
address from;
bytes32 rights;
address contract_;
uint256 tokenId;
uint256 amount;
}
/// @notice Emitted when an address delegates or revokes rights for their entire wallet
event DelegateAll(address indexed from, address indexed to, bytes32 rights, bool enable);
/// @notice Emitted when an address delegates or revokes rights for a contract address
event DelegateContract(
address indexed from, address indexed to, address indexed contract_, bytes32 rights, bool enable
);
/// @notice Emitted when an address delegates or revokes rights for an ERC721 tokenId
event DelegateERC721(
address indexed from,
address indexed to,
address indexed contract_,
uint256 tokenId,
bytes32 rights,
bool enable
);
/// @notice Emitted when an address delegates or revokes rights for an amount of ERC20 tokens
event DelegateERC20(
address indexed from, address indexed to, address indexed contract_, bytes32 rights, uint256 amount
);
/// @notice Emitted when an address delegates or revokes rights for an amount of an ERC1155 tokenId
event DelegateERC1155(
address indexed from,
address indexed to,
address indexed contract_,
uint256 tokenId,
bytes32 rights,
uint256 amount
);
/// @notice Thrown if multicall calldata is malformed
error MulticallFailed();
/**
* ----------- WRITE -----------
*/
/**
* @notice Call multiple functions in the current contract and return the data from all of them if they all succeed
* @param data The encoded function data for each of the calls to make to this contract
* @return results The results from each of the calls passed in via data
*/
function multicall(bytes[] calldata data) external payable returns (bytes[] memory results);
/**
* @notice Allow the delegate to act on behalf of `msg.sender` for all contracts
* @param to The address to act as delegate
* @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights
* @param enable Whether to enable or disable this delegation, true delegates and false revokes
* @return delegationHash The unique identifier of the delegation
*/
function delegateAll(address to, bytes32 rights, bool enable) external payable returns (bytes32 delegationHash);
/**
* @notice Allow the delegate to act on behalf of `msg.sender` for a specific contract
* @param to The address to act as delegate
* @param contract_ The contract whose rights are being delegated
* @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights
* @param enable Whether to enable or disable this delegation, true delegates and false revokes
* @return delegationHash The unique identifier of the delegation
*/
function delegateContract(address to, address contract_, bytes32 rights, bool enable)
external
payable
returns (bytes32 delegationHash);
/**
* @notice Allow the delegate to act on behalf of `msg.sender` for a specific ERC721 token
* @param to The address to act as delegate
* @param contract_ The contract whose rights are being delegated
* @param tokenId The token id to delegate
* @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights
* @param enable Whether to enable or disable this delegation, true delegates and false revokes
* @return delegationHash The unique identifier of the delegation
*/
function delegateERC721(address to, address contract_, uint256 tokenId, bytes32 rights, bool enable)
external
payable
returns (bytes32 delegationHash);
/**
* @notice Allow the delegate to act on behalf of `msg.sender` for a specific amount of ERC20 tokens
* @dev The actual amount is not encoded in the hash, just the existence of a amount (since it is an upper bound)
* @param to The address to act as delegate
* @param contract_ The address for the fungible token contract
* @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights
* @param amount The amount to delegate, > 0 delegates and 0 revokes
* @return delegationHash The unique identifier of the delegation
*/
function delegateERC20(address to, address contract_, bytes32 rights, uint256 amount)
external
payable
returns (bytes32 delegationHash);
/**
* @notice Allow the delegate to act on behalf of `msg.sender` for a specific amount of ERC1155 tokens
* @dev The actual amount is not encoded in the hash, just the existence of a amount (since it is an upper bound)
* @param to The address to act as delegate
* @param contract_ The address of the contract that holds the token
* @param tokenId The token id to delegate
* @param rights Specific subdelegation rights granted to the delegate, pass an empty bytestring to encompass all rights
* @param amount The amount of that token id to delegate, > 0 delegates and 0 revokes
* @return delegationHash The unique identifier of the delegation
*/
function delegateERC1155(address to, address contract_, uint256 tokenId, bytes32 rights, uint256 amount)
external
payable
returns (bytes32 delegationHash);
/**
* ----------- CHECKS -----------
*/
/**
* @notice Check if `to` is a delegate of `from` for the entire wallet
* @param to The potential delegate address
* @param from The potential address who delegated rights
* @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only
* @return valid Whether delegate is granted to act on the from's behalf
*/
function checkDelegateForAll(address to, address from, bytes32 rights) external view returns (bool);
/**
* @notice Check if `to` is a delegate of `from` for the specified `contract_` or the entire wallet
* @param to The delegated address to check
* @param contract_ The specific contract address being checked
* @param from The cold wallet who issued the delegation
* @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only
* @return valid Whether delegate is granted to act on from's behalf for entire wallet or that specific contract
*/
function checkDelegateForContract(address to, address from, address contract_, bytes32 rights)
external
view
returns (bool);
/**
* @notice Check if `to` is a delegate of `from` for the specific `contract` and `tokenId`, the entire `contract_`, or the entire wallet
* @param to The delegated address to check
* @param contract_ The specific contract address being checked
* @param tokenId The token id for the token to delegating
* @param from The wallet that issued the delegation
* @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only
* @return valid Whether delegate is granted to act on from's behalf for entire wallet, that contract, or that specific tokenId
*/
function checkDelegateForERC721(address to, address from, address contract_, uint256 tokenId, bytes32 rights)
external
view
returns (bool);
/**
* @notice Returns the amount of ERC20 tokens the delegate is granted rights to act on the behalf of
* @param to The delegated address to check
* @param contract_ The address of the token contract
* @param from The cold wallet who issued the delegation
* @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only
* @return balance The delegated balance, which will be 0 if the delegation does not exist
*/
function checkDelegateForERC20(address to, address from, address contract_, bytes32 rights)
external
view
returns (uint256);
/**
* @notice Returns the amount of a ERC1155 tokens the delegate is granted rights to act on the behalf of
* @param to The delegated address to check
* @param contract_ The address of the token contract
* @param tokenId The token id to check the delegated amount of
* @param from The cold wallet who issued the delegation
* @param rights Specific rights to check for, pass the zero value to ignore subdelegations and check full delegations only
* @return balance The delegated balance, which will be 0 if the delegation does not exist
*/
function checkDelegateForERC1155(address to, address from, address contract_, uint256 tokenId, bytes32 rights)
external
view
returns (uint256);
/**
* ----------- ENUMERATIONS -----------
*/
/**
* @notice Returns all enabled delegations a given delegate has received
* @param to The address to retrieve delegations for
* @return delegations Array of Delegation structs
*/
function getIncomingDelegations(address to) external view returns (Delegation[] memory delegations);
/**
* @notice Returns all enabled delegations an address has given out
* @param from The address to retrieve delegations for
* @return delegations Array of Delegation structs
*/
function getOutgoingDelegations(address from) external view returns (Delegation[] memory delegations);
/**
* @notice Returns all hashes associated with enabled delegations an address has received
* @param to The address to retrieve incoming delegation hashes for
* @return delegationHashes Array of delegation hashes
*/
function getIncomingDelegationHashes(address to) external view returns (bytes32[] memory delegationHashes);
/**
* @notice Returns all hashes associated with enabled delegations an address has given out
* @param from The address to retrieve outgoing delegation hashes for
* @return delegationHashes Array of delegation hashes
*/
function getOutgoingDelegationHashes(address from) external view returns (bytes32[] memory delegationHashes);
/**
* @notice Returns the delegations for a given array of delegation hashes
* @param delegationHashes is an array of hashes that correspond to delegations
* @return delegations Array of Delegation structs, return empty structs for nonexistent or revoked delegations
*/
function getDelegationsFromHashes(bytes32[] calldata delegationHashes)
external
view
returns (Delegation[] memory delegations);
/**
* ----------- STORAGE ACCESS -----------
*/
/**
* @notice Allows external contracts to read arbitrary storage slots
*/
function readSlot(bytes32 location) external view returns (bytes32);
/**
* @notice Allows external contracts to read an arbitrary array of storage slots
*/
function readSlots(bytes32[] calldata locations) external view returns (bytes32[] memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
interface IExclusiveDelegateResolver {
function exclusiveOwnerByRights(address contractAddress, uint256 tokenId, bytes24 rights)
external
view
returns (address);
function generateRightsWithExpiration(bytes24 rightsIdentifier, uint40 expiration)
external
view
returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
interface ILayerZeroEndpointLocator {
function endpoint() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
interface INFTShadow is IERC721 {
function read(uint256[] calldata tokenIds, uint32[] calldata eids) external payable returns (bytes32);
function readWithCallback(uint256[] calldata tokenIds, uint32[] calldata eids, uint128 callbackGasLimit)
external
payable
returns (bytes32);
function burn(uint256 tokenId) external;
function send(
uint32 eid,
uint256[] calldata tokenIds,
address beneficiary,
address refundRecipient,
uint128 supplementalGasLimit
) external payable;
function executeCallback(bytes32 guid) external;
function locked(uint256 tokenId) external view returns (bool);
function shadowModeEnabled() external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.29;
struct CollectionConfig {
uint32 baseCollectionChainId;
uint32 baseCollectionEid;
uint32 baseCollectionPerNftOwnershipUpdateCost; // cost of transferring an NFT from the base collection. If 0, default of 100_000 is used
address shadowAddress; // Local shadow address for this chain
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.29;
library SafeCall {
/// @notice calls a contract with a specified gas limit and value and captures the return data
/// @dev copied from https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol.
/// @param _target The address to call
/// @param _gas The amount of gas to forward to the remote contract
/// @param _value The value in wei to send to the remote contract
/// @param _maxCopy The maximum number of bytes of returndata to copy
/// to memory.
/// @param _calldata The data to send to the remote contract
/// @return success and returndata, as `.call()`. Returndata is capped to
/// `_maxCopy` bytes.
function safeCall(address _target, uint256 _gas, uint256 _value, uint16 _maxCopy, bytes memory _calldata)
internal
returns (bool, bytes memory)
{
// set up for assembly call
uint256 _toCopy;
bool _success;
bytes memory _returnData = new bytes(_maxCopy);
// dispatch message to recipient
// by assembly calling "handle" function
// we call via assembly to avoid memcopying a very large returndata
// returned by a malicious contract
assembly {
_success :=
call(
_gas, // gas
_target, // recipient
_value, // ether value
add(_calldata, 0x20), // inloc
mload(_calldata), // inlen
0, // outloc
0 // outlen
)
// limit our copy to 256 bytes
_toCopy := returndatasize()
if gt(_toCopy, _maxCopy) { _toCopy := _maxCopy }
// Store the length of the copied bytes
mstore(_returnData, _toCopy)
// copy the bytes from returndata[0:_toCopy]
returndatacopy(add(_returnData, 0x20), 0, _toCopy)
}
return (_success, _returnData);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for storage of packed unsigned integers.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibMap.sol)
library LibMap {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev A uint8 map in storage.
struct Uint8Map {
mapping(uint256 => uint256) map;
}
/// @dev A uint16 map in storage.
struct Uint16Map {
mapping(uint256 => uint256) map;
}
/// @dev A uint32 map in storage.
struct Uint32Map {
mapping(uint256 => uint256) map;
}
/// @dev A uint40 map in storage. Useful for storing timestamps up to 34841 A.D.
struct Uint40Map {
mapping(uint256 => uint256) map;
}
/// @dev A uint64 map in storage.
struct Uint64Map {
mapping(uint256 => uint256) map;
}
/// @dev A uint128 map in storage.
struct Uint128Map {
mapping(uint256 => uint256) map;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* GETTERS / SETTERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the uint8 value at `index` in `map`.
function get(Uint8Map storage map, uint256 index) internal view returns (uint8 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, map.slot)
mstore(0x00, shr(5, index))
result := byte(and(31, not(index)), sload(keccak256(0x00, 0x40)))
}
}
/// @dev Updates the uint8 value at `index` in `map`.
function set(Uint8Map storage map, uint256 index, uint8 value) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, map.slot)
mstore(0x00, shr(5, index))
let s := keccak256(0x00, 0x40) // Storage slot.
mstore(0x00, sload(s))
mstore8(and(31, not(index)), value)
sstore(s, mload(0x00))
}
}
/// @dev Returns the uint16 value at `index` in `map`.
function get(Uint16Map storage map, uint256 index) internal view returns (uint16 result) {
result = uint16(map.map[index >> 4] >> ((index & 15) << 4));
}
/// @dev Updates the uint16 value at `index` in `map`.
function set(Uint16Map storage map, uint256 index, uint16 value) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, map.slot)
mstore(0x00, shr(4, index))
let s := keccak256(0x00, 0x40) // Storage slot.
let o := shl(4, and(index, 15)) // Storage slot offset (bits).
let v := sload(s) // Storage slot value.
let m := 0xffff // Value mask.
sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value)))))
}
}
/// @dev Returns the uint32 value at `index` in `map`.
function get(Uint32Map storage map, uint256 index) internal view returns (uint32 result) {
result = uint32(map.map[index >> 3] >> ((index & 7) << 5));
}
/// @dev Updates the uint32 value at `index` in `map`.
function set(Uint32Map storage map, uint256 index, uint32 value) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, map.slot)
mstore(0x00, shr(3, index))
let s := keccak256(0x00, 0x40) // Storage slot.
let o := shl(5, and(index, 7)) // Storage slot offset (bits).
let v := sload(s) // Storage slot value.
let m := 0xffffffff // Value mask.
sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value)))))
}
}
/// @dev Returns the uint40 value at `index` in `map`.
function get(Uint40Map storage map, uint256 index) internal view returns (uint40 result) {
unchecked {
result = uint40(map.map[index / 6] >> ((index % 6) * 40));
}
}
/// @dev Updates the uint40 value at `index` in `map`.
function set(Uint40Map storage map, uint256 index, uint40 value) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, map.slot)
mstore(0x00, div(index, 6))
let s := keccak256(0x00, 0x40) // Storage slot.
let o := mul(40, mod(index, 6)) // Storage slot offset (bits).
let v := sload(s) // Storage slot value.
let m := 0xffffffffff // Value mask.
sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value)))))
}
}
/// @dev Returns the uint64 value at `index` in `map`.
function get(Uint64Map storage map, uint256 index) internal view returns (uint64 result) {
result = uint64(map.map[index >> 2] >> ((index & 3) << 6));
}
/// @dev Updates the uint64 value at `index` in `map`.
function set(Uint64Map storage map, uint256 index, uint64 value) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, map.slot)
mstore(0x00, shr(2, index))
let s := keccak256(0x00, 0x40) // Storage slot.
let o := shl(6, and(index, 3)) // Storage slot offset (bits).
let v := sload(s) // Storage slot value.
let m := 0xffffffffffffffff // Value mask.
sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value)))))
}
}
/// @dev Returns the uint128 value at `index` in `map`.
function get(Uint128Map storage map, uint256 index) internal view returns (uint128 result) {
result = uint128(map.map[index >> 1] >> ((index & 1) << 7));
}
/// @dev Updates the uint128 value at `index` in `map`.
function set(Uint128Map storage map, uint256 index, uint128 value) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, map.slot)
mstore(0x00, shr(1, index))
let s := keccak256(0x00, 0x40) // Storage slot.
let o := shl(7, and(index, 1)) // Storage slot offset (bits).
let v := sload(s) // Storage slot value.
let m := 0xffffffffffffffffffffffffffffffff // Value mask.
sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value)))))
}
}
/// @dev Returns the value at `index` in `map`.
function get(mapping(uint256 => uint256) storage map, uint256 index, uint256 bitWidth)
internal
view
returns (uint256 result)
{
unchecked {
uint256 d = _rawDiv(256, bitWidth); // Bucket size.
uint256 m = (1 << bitWidth) - 1; // Value mask.
result = (map[_rawDiv(index, d)] >> (_rawMod(index, d) * bitWidth)) & m;
}
}
/// @dev Updates the value at `index` in `map`.
function set(
mapping(uint256 => uint256) storage map,
uint256 index,
uint256 value,
uint256 bitWidth
) internal {
unchecked {
uint256 d = _rawDiv(256, bitWidth); // Bucket size.
uint256 m = (1 << bitWidth) - 1; // Value mask.
uint256 o = _rawMod(index, d) * bitWidth; // Storage slot offset (bits).
map[_rawDiv(index, d)] ^= (((map[_rawDiv(index, d)] >> o) ^ value) & m) << o;
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BINARY SEARCH */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// The following functions search in the range of [`start`, `end`)
// (i.e. `start <= index < end`).
// The range must be sorted in ascending order.
// `index` precedence: equal to > nearest before > nearest after.
// An invalid search range will simply return `(found = false, index = start)`.
/// @dev Returns whether `map` contains `needle`, and the index of `needle`.
function searchSorted(Uint8Map storage map, uint8 needle, uint256 start, uint256 end)
internal
view
returns (bool found, uint256 index)
{
return searchSorted(map.map, needle, start, end, 8);
}
/// @dev Returns whether `map` contains `needle`, and the index of `needle`.
function searchSorted(Uint16Map storage map, uint16 needle, uint256 start, uint256 end)
internal
view
returns (bool found, uint256 index)
{
return searchSorted(map.map, needle, start, end, 16);
}
/// @dev Returns whether `map` contains `needle`, and the index of `needle`.
function searchSorted(Uint32Map storage map, uint32 needle, uint256 start, uint256 end)
internal
view
returns (bool found, uint256 index)
{
return searchSorted(map.map, needle, start, end, 32);
}
/// @dev Returns whether `map` contains `needle`, and the index of `needle`.
function searchSorted(Uint40Map storage map, uint40 needle, uint256 start, uint256 end)
internal
view
returns (bool found, uint256 index)
{
return searchSorted(map.map, needle, start, end, 40);
}
/// @dev Returns whether `map` contains `needle`, and the index of `needle`.
function searchSorted(Uint64Map storage map, uint64 needle, uint256 start, uint256 end)
internal
view
returns (bool found, uint256 index)
{
return searchSorted(map.map, needle, start, end, 64);
}
/// @dev Returns whether `map` contains `needle`, and the index of `needle`.
function searchSorted(Uint128Map storage map, uint128 needle, uint256 start, uint256 end)
internal
view
returns (bool found, uint256 index)
{
return searchSorted(map.map, needle, start, end, 128);
}
/// @dev Returns whether `map` contains `needle`, and the index of `needle`.
function searchSorted(
mapping(uint256 => uint256) storage map,
uint256 needle,
uint256 start,
uint256 end,
uint256 bitWidth
) internal view returns (bool found, uint256 index) {
unchecked {
if (start >= end) end = start;
uint256 t;
uint256 o = start - 1; // Offset to derive the actual index.
uint256 l = 1; // Low.
uint256 d = _rawDiv(256, bitWidth); // Bucket size.
uint256 m = (1 << bitWidth) - 1; // Value mask.
uint256 h = end - start; // High.
while (true) {
index = (l & h) + ((l ^ h) >> 1);
if (l > h) break;
t = (map[_rawDiv(index + o, d)] >> (_rawMod(index + o, d) * bitWidth)) & m;
if (t == needle) break;
if (needle <= t) h = index - 1;
else l = index + 1;
}
/// @solidity memory-safe-assembly
assembly {
m := or(iszero(index), iszero(bitWidth))
found := iszero(or(xor(t, needle), m))
index := add(o, xor(index, mul(xor(index, 1), m)))
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PRIVATE HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `x / y`, returning 0 if `y` is zero.
function _rawDiv(uint256 x, uint256 y) private pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(x, y)
}
}
/// @dev Returns `x % y`, returning 0 if `y` is zero.
function _rawMod(uint256 x, uint256 y) private pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mod(x, y)
}
}
}// SPDX-License-Identifier: Unlicense /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ pragma solidity >=0.8.0 <0.9.0; library BytesLib { function concat( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore(0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. )) } return tempBytes; } function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and( fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 ), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) { require(_bytes.length >= _start + 1 , "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equalStorage( bytes storage _preBytes, bytes memory _postBytes ) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for {} eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } }
{
"optimizer": {
"enabled": true,
"runs": 200
},
"viaIR": true,
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_endpointLocator","type":"address"},{"internalType":"address","name":"_delegate","type":"address"},{"internalType":"uint32","name":"_readChannel","type":"uint32"},{"internalType":"address","name":"_delegatexyz","type":"address"},{"internalType":"address","name":"_exclusiveDelegateResolver","type":"address"},{"internalType":"address","name":"_initialAdmin","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"BeneficiaryZeroAddress","type":"error"},{"inputs":[],"name":"BurnFailed","type":"error"},{"inputs":[],"name":"CollectionAlreadyRegistered","type":"error"},{"inputs":[],"name":"CollectionNotInShadowMode","type":"error"},{"inputs":[],"name":"ContractNotConfigured","type":"error"},{"inputs":[],"name":"InvalidCaller","type":"error"},{"inputs":[],"name":"InvalidChain","type":"error"},{"inputs":[],"name":"InvalidDelegate","type":"error"},{"inputs":[],"name":"InvalidEid","type":"error"},{"inputs":[],"name":"InvalidEndpointCall","type":"error"},{"inputs":[{"internalType":"uint16","name":"optionType","type":"uint16"}],"name":"InvalidOptionType","type":"error"},{"inputs":[{"internalType":"bytes","name":"options","type":"bytes"}],"name":"InvalidOptions","type":"error"},{"inputs":[],"name":"InvalidOwner","type":"error"},{"inputs":[],"name":"InvalidPayloadHash","type":"error"},{"inputs":[],"name":"InvalidReadChannel","type":"error"},{"inputs":[],"name":"LzTokenUnavailable","type":"error"},{"inputs":[],"name":"MaxLzReceiveGasAllocationExceeded","type":"error"},{"inputs":[],"name":"MintFailed","type":"error"},{"inputs":[],"name":"MismatchedCollectionAddress","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":[{"internalType":"address","name":"addr","type":"address"}],"name":"OnlyEndpoint","type":"error"},{"inputs":[],"name":"OnlyInternalCalls","type":"error"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"}],"name":"OnlyPeer","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":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"StaleReadRequest","type":"error"},{"inputs":[],"name":"TransferFailed","type":"error"},{"inputs":[],"name":"UnauthorizedExecutor","type":"error"},{"inputs":[],"name":"UnlockFailed","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroLengthArray","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"executor","type":"address"},{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"AllowedExecutorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"srcEid","type":"uint32"},{"indexed":true,"internalType":"bytes32","name":"sender","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"nonce","type":"uint64"}],"name":"CachedMessageExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collectionAddress","type":"address"},{"indexed":true,"internalType":"address","name":"baseCollectionAddress","type":"address"},{"indexed":true,"internalType":"uint32","name":"baseCollectionEid","type":"uint32"}],"name":"CollectionRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"enforceExecutors","type":"bool"}],"name":"EnforceExecutionSet","type":"event"},{"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":true,"internalType":"uint32","name":"srcEid","type":"uint32"},{"indexed":true,"internalType":"bytes32","name":"sender","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"nonce","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"reason","type":"bytes"}],"name":"MessageCached","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":"uint32","name":"readChannel","type":"uint32"}],"name":"ReadChannelSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"baseCollectionAddress","type":"address"},{"indexed":true,"internalType":"address","name":"shadowCollectionAddress","type":"address"},{"indexed":false,"internalType":"uint32[]","name":"eids","type":"uint32[]"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"ReadTriggered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"eid","type":"uint32"},{"indexed":false,"internalType":"uint16","name":"confirmations","type":"uint16"}],"name":"RequiredConfirmationsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"eid","type":"uint32"},{"indexed":true,"internalType":"address","name":"baseCollectionAddress","type":"address"},{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"indexed":false,"internalType":"address","name":"beneficiary","type":"address"}],"name":"Sent","type":"event"},{"inputs":[],"name":"COLLECTION_REGISTRAR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DELEGATE_REGISTRY_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXCLUSIVE_DELEGATE_RESOLVER_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHADOW_TOKEN_RIGHTS","outputs":[{"internalType":"bytes24","name":"","type":"bytes24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"THIS_CONTRACT_EID","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"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":[{"internalType":"address","name":"executor","type":"address"}],"name":"allowedExecutors","outputs":[{"internalType":"bool","name":"allowed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"baseCollectionAddress","type":"address"}],"name":"baseToShadow","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"baseCollectionAddress","type":"address"}],"name":"collectionConfigs","outputs":[{"internalType":"uint32","name":"baseCollectionChainId","type":"uint32"},{"internalType":"uint32","name":"baseCollectionEid","type":"uint32"},{"internalType":"uint32","name":"baseCollectionPerNftOwnershipUpdateCost","type":"uint32"},{"internalType":"address","name":"shadowAddress","type":"address"}],"stateMutability":"view","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":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"delegatedOwners","outputs":[{"internalType":"address","name":"delegatedOwner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endpoint","outputs":[{"internalType":"contract ILayerZeroEndpointV2","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"enforceExecutors","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"uint16","name":"msgType","type":"uint16"}],"name":"enforcedOptions","outputs":[{"internalType":"bytes","name":"enforcedOption","type":"bytes"}],"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"}],"name":"executeMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"baseCollectionAddress","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint128","name":"supplementalGasLimit","type":"uint128"}],"name":"getReadOptions","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"address","name":"baseCollectionAddress","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint128","name":"supplementalGasLimit","type":"uint128"}],"name":"getSendOptions","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"guid","type":"bytes32"}],"name":"initTimestamps","outputs":[{"internalType":"uint256","name":"timestamp","type":"uint256"}],"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":"","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":"bytes","name":"_request","type":"bytes"},{"internalType":"bytes","name":"_response","type":"bytes"}],"name":"lzMap","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"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":[{"internalType":"bytes","name":"_request","type":"bytes"},{"internalType":"bytes[]","name":"_responses","type":"bytes[]"}],"name":"lzReduce","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"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":"oAppVersion","outputs":[{"internalType":"uint64","name":"senderVersion","type":"uint64"},{"internalType":"uint64","name":"receiverVersion","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint64","name":"","type":"uint64"}],"name":"payloadHashes","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"}],"name":"peers","outputs":[{"internalType":"bytes32","name":"peer","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"baseCollectionAddress","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint32[]","name":"dstEids","type":"uint32[]"},{"internalType":"uint128","name":"supplementalGasLimit","type":"uint128"}],"name":"quoteRead","outputs":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"address","name":"baseCollectionAddress","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint128","name":"supplementalGasLimit","type":"uint128"}],"name":"quoteSend","outputs":[{"internalType":"uint256","name":"nativeFee","type":"uint256"},{"internalType":"uint256","name":"lzTokenFee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"baseCollectionAddress","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint32[]","name":"eids","type":"uint32[]"},{"internalType":"address","name":"refundRecipient","type":"address"},{"internalType":"uint128","name":"supplementalGasLimit","type":"uint128"}],"name":"read","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"readChannel","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"shadowCollectionAddress","type":"address"},{"internalType":"uint32","name":"baseCollectionChainId","type":"uint32"},{"internalType":"address","name":"baseCollectionAddress","type":"address"},{"internalType":"uint32","name":"baseCollectionEid","type":"uint32"},{"internalType":"uint32","name":"baseCollectionPerNftOwnershipUpdateCost","type":"uint32"}],"name":"registerCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"}],"name":"requiredConfirmations","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"srcEid","type":"uint32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"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"}],"name":"retryFailedMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"dstEid","type":"uint32"},{"internalType":"address","name":"baseCollectionAddress","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"address","name":"refundRecipient","type":"address"},{"internalType":"uint128","name":"supplementalGasLimit","type":"uint128"}],"name":"send","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"executor","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"setAllowedExecutor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"baseCollectionAddress","type":"address"},{"internalType":"uint32","name":"cost","type":"uint32"}],"name":"setBaseCollectionPerNftOwnershipUpdateCost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_delegate","type":"address"}],"name":"setDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_enforceExecutors","type":"bool"}],"name":"setEnforceExecutors","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":"uint32","name":"_eid","type":"uint32"},{"internalType":"bytes32","name":"_peer","type":"bytes32"}],"name":"setPeer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_readChannel","type":"uint32"}],"name":"setReadChannel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_channelId","type":"uint32"},{"internalType":"bool","name":"_active","type":"bool"}],"name":"setReadChannel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"eid","type":"uint32"},{"internalType":"uint16","name":"confirmations","type":"uint16"}],"name":"setRequiredConfirmations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"shadowCollectionAddress","type":"address"}],"name":"shadowToBase","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"baseCollectionAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes24","name":"rightsIdentifier","type":"bytes24"}],"name":"unlockedExclusiveOwnerByRights","outputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"bool","name":"_isLocked","type":"bool"}],"stateMutability":"view","type":"function"}]Contract Creation Code
61012080604052346104395760009060c0816156d08038038091610023828561043e565b8339810103126104355761003681610477565b9061004360208201610477565b61004f6040830161048b565b61005b60608401610477565b9061007460a061006d60808701610477565b9501610477565b604051635e280f1160e01b815290956001600160a01b031693602082600481885afa91821561042a5788926103ea575b506001600160a01b0387169182156103d65788546001600160a01b0319811684178a5560405193906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08b80a36001600160a01b039081166080819052911680156103c757908891813b156103c3578383819360249363ca5eb5e160e01b845260048401525af180156103b8576103a0575b5063ffffffff169263fffff9be841115610391579160209160049360e0526101005260405182810146815283825261017760408361043e565b905190206001600160401b03191660a052604051635e280f1160e01b815292839182905afa908115610347578491610352575b5060405163416ecebf60e01b815290602090829060049082906001600160a01b03165afa9081156103475784916102db575b7f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b60408661022687878760c05263ffffffff1960045416176004556102208161049c565b5061053a565b5063ffffffff6004541690818152600160205282309120558151908152306020820152a16040516150bf90816105b1823960805181818161075201528181610de601528181611a8f01528181613673015281816140b901526146d6015260a0518181816110300152613318015260c0518181816106360152818161180901528181611d1401528181611eb70152613363015260e0518181816109b00152612644015261010051818181610e2b0152614d2a0152f35b90506020813d60201161033f575b816102f66020938361043e565b8101031261033b576040927f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b94926103306102269361048b565b9250929450926101dc565b8380fd5b3d91506102e9565b6040513d86823e3d90fd5b90506020813d602011610389575b8161036d6020938361043e565b8101031261033b576020610382600492610477565b91506101aa565b3d9150610360565b633df6e48d60e21b8652600486fd5b956103b18163ffffffff939861043e565b959061013e565b6040513d89823e3d90fd5b8280fd5b632d618d8160e21b8952600489fd5b631e4fbdf760e01b89526004899052602489fd5b9091506020813d602011610422575b816104066020938361043e565b8101031261041e5761041790610477565b90386100a4565b8780fd5b3d91506103f9565b6040513d8a823e3d90fd5b5080fd5b600080fd5b601f909101601f19168101906001600160401b0382119082101761046157604052565b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b038216820361043957565b519063ffffffff8216820361043957565b6001600160a01b0381166000908152600080516020615690833981519152602052604090205460ff16610534576001600160a01b0316600081815260008051602061569083398151915260205260408120805460ff191660011790553391907f8970ff45bc1804c7a79662cce9df9b0403588be8e486c6f5a410a2814caa892c906000805160206156708339815191529080a4600190565b50600090565b6001600160a01b03811660009081526000805160206156b0833981519152602052604090205460ff16610534576001600160a01b031660008181526000805160206156b083398151915260205260408120805460ff191660011790553391906000805160206156708339815191528180a460019056fe6080604052600436101561001257600080fd5b60003560e01c806301a0de051461038757806301ffc9a71461038257806304bd49a51461037d578063066d591014610378578063108dcbdd1461037357806313137d651461036e57806317442b70146103695780631d56672114610364578063248a9ca31461035f5780632f2ff15d1461035a5780633400288b146103555780633530511a1461035057806336568abe1461034b57806336b1dd211461034657806337cb6736146103415780634202fce11461033c57806345248a3714610337578063461572f91461033257806347c1b3171461032d5780635535d461146103285780635e280f11146103235780636a4d86721461031e5780636eaa6904146103195780636fe87dba14610314578063715018a61461030f5780637d25a05e1461030a57806382413eac14610305578063864c651514610300578063881ae9f8146102fb5780638da5cb5b146102f657806391d14854146102f157806399315160146102ec578063a0238f3e146102e7578063a217fddf146102e2578063a34ac81b146102dd578063ade7142d146102d8578063b33b522d146102d3578063b98bd070146102ce578063bb0b6a53146102c9578063bc70b354146102c4578063c9df8167146102bf578063ca5eb5e1146102ba578063cfac96ce146102b5578063d1e1d0cc146102b0578063d547741f146102ab578063da383b97146102a6578063e052778a146102a1578063e60c287c1461029c578063eba1cf0814610297578063f0a9e48114610292578063f17488351461028d578063f1c418ee14610288578063f2fde38b14610283578063fe084c8f1461027e5763ff7bd03d1461027957600080fd5b61235f565b612157565b6120ca565b6120a7565b612062565b61201a565b611fbb565b611f5c565b611f21565b611c61565b611c1e565b611b9a565b611b0d565b611a65565b611781565b61172d565b6116f2565b6115ed565b61157a565b6114e3565b611479565b61145d565b611405565b611287565b611231565b611208565b6111a6565b611132565b6110d4565b6110ad565b611054565b61100f565b610e6b565b610e15565b610dd0565b610d76565b610b8b565b610b67565b610af6565b610ac5565b6109df565b61099a565b610950565b6108f5565b6108c4565b61086e565b610839565b61080d565b6107eb565b6106e9565b61065a565b610619565b6104b9565b6103f1565b6103a2565b6001600160a01b0381160361039d57565b600080fd5b3461039d57604036600319011261039d576004356103bf8161038c565b6001600160a01b0390811660009081526007602090815260408083206024358452825291829020549151919092168152f35b3461039d57602036600319011261039d5760043563ffffffff60e01b811680910361039d57602090637965db0b60e01b8114908115610436575b506040519015158152f35b6301ffc9a760e01b1490503861042b565b9181601f8401121561039d578235916001600160401b03831161039d576020808501948460051b01011161039d57565b606435906001600160801b038216820361039d57565b60a435906001600160801b038216820361039d57565b608435906001600160801b038216820361039d57565b3461039d57608036600319011261039d576004356104d68161038c565b6024356001600160401b03811161039d576104f5903690600401610447565b91906044356001600160401b03811161039d57610516903690600401610447565b9361051f610477565b6001600160a01b0385166000908152600560205260409020610543905b5460601c90565b916001600160a01b038316156105fe5761056881866105999960009761057e976132f3565b9461057860045463ffffffff1690565b96612914565b60405180958192632f1c2cd560e21b83528660048401612476565b0381305afa9182156105f9576105b7936000936105d4575b5061360f565b8051602091820151604080519283529282015290819081015b0390f35b6105f29193503d806000833e6105ea8183610cb1565b810190612451565b91386105b1565b61249a565b622dc1c960e71b60005260046000fd5b600091031261039d57565b3461039d57600036600319011261039d57602060405163ffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b3461039d57602036600319011261039d576004356106778161038c565b60018060a01b03166000526005602052602060406000205460601c604051908152f35b606090600319011261039d57600490565b606090606319011261039d57606490565b9181601f8401121561039d578235916001600160401b03831161039d576020838186019501011161039d57565b60e036600319011261039d576106fe3661069a565b6064356084356001600160401b03811161039d576107209036906004016106bc565b9060a4359261072e8461038c565b60c4356001600160401b03811161039d5761074d9036906004016106bc565b5050337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316036107d65784359461078b866108b6565b610794866136d8565b9560208201358097036107ae57506107ac9550613753565b005b63ffffffff816107be89936108b6565b63309afaf360e21b6000521660045260245260446000fd5b6391ac5e4f60e01b6000523360045260246000fd5b3461039d57600036600319011261039d57604080516001815260026020820152f35b3461039d57602036600319011261039d57600435600052600a6020526020604060002054604051908152f35b3461039d57602036600319011261039d576020610866600435600052600360205260016040600020015490565b604051908152f35b3461039d57604036600319011261039d576107ac6024356004356108918261038c565b6108b16108ac82600052600360205260016040600020015490565b613929565b613966565b63ffffffff81160361039d57565b3461039d57604036600319011261039d576107ac6004356108e4816108b6565b602435906108f06139fa565b613a23565b3461039d57606036600319011261039d576004356109128161038c565b60443560243567ffffffffffffffff198216820361039d576109339261252a565b604080516001600160a01b03939093168352901515602083015290f35b3461039d57604036600319011261039d576004356024356109708161038c565b336001600160a01b03821603610989576107ac91613a6b565b63334bd91960e11b60005260046000fd5b3461039d57600036600319011261039d576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461039d57602036600319011261039d576004356109fc8161038c565b60018060a01b03166000526009602052602060ff604060002054166040519015158152f35b608060031982011261039d57600435610a39816108b6565b91602435610a468161038c565b91604435906001600160401b03821161039d57610a6591600401610447565b90916064356001600160801b038116810361039d5790565b60005b838110610a905750506000910152565b8181015183820152602001610a80565b90602091610ab981518092818552858086019101610a7d565b601f01601f1916010190565b3461039d576105d0610ae2610ad936610a21565b939290926127bd565b604051918291602083526020830190610aa0565b3461039d57610b0436610a21565b6001600160a01b0380851660009081526005602052604090209195949391610b2b9061053c565b16156105fe576105999460009261057e9260405195610b6187610b5385858560208501612890565b03601f198101895288610cb1565b876127bd565b3461039d57600036600319011261039d57602063ffffffff60045416604051908152f35b3461039d57606036600319011261039d57600435610ba88161038c565b6024356001600160401b03811161039d57610bc7903690600401610447565b909190604435906001600160801b038216820361039d576105d093610ae293612914565b6024359061ffff8216820361039d57565b359061ffff8216820361039d57565b90600182811c92168015610c3b575b6020831014610c2557565b634e487b7160e01b600052602260045260246000fd5b91607f1691610c1a565b634e487b7160e01b600052604160045260246000fd5b606081019081106001600160401b03821117610c7657604052565b610c45565b60e081019081106001600160401b03821117610c7657604052565b604081019081106001600160401b03821117610c7657604052565b90601f801991011681019081106001600160401b03821117610c7657604052565b9060405191826000825492610ce684610c0b565b8084529360018116908115610d545750600114610d0d575b50610d0b92500383610cb1565b565b90506000929192526020600020906000915b818310610d38575050906020610d0b9282010138610cfe565b6020919350806001915483858901015201910190918492610d1f565b905060209250610d0b94915060ff191682840152151560051b82010138610cfe565b3461039d57604036600319011261039d576105d0610ae2610dcb600435610d9c816108b6565b63ffffffff610da9610beb565b9116600052600260205260406000209061ffff16600052602052604060002090565b610cd2565b3461039d57600036600319011261039d576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461039d57600036600319011261039d576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b6001600160401b0381160361039d57565b3461039d5761010036600319011261039d57600435610e89816108b6565b60243590604435610e9981610e5a565b610ea2366106ab565b9160c43560e4356001600160401b03811161039d57610ec59036906004016106bc565b909463ffffffff84169563fffff9be8711610ffe57610f0c92610efe916040519586946304c98a8b60e51b6020870152602486016129e8565b03601f198101835282610cb1565b6040516020810190610f2481610efe46863087612a3a565b519020610f7084610f5888610f498763ffffffff166000526008602052604060002090565b90600052602052604060002090565b906001600160401b0316600052602052604060002090565b5403610fed576000610f9d84610f5888610f49610fa59763ffffffff166000526008602052604060002090565b555a30613ca4565b9015610fe557506040516001600160401b039190911681527f49a5bb7337668613a742dc30346f29d11f0b4d4a2c0745a08afccc9bb6cea3d090602090a3005b805190602001fd5b63a84ab60d60e01b60005260046000fd5b634d30e69360e11b60005260046000fd5b3461039d57600036600319011261039d5760206040516001600160401b03197f0000000000000000000000000000000000000000000000000000000000000000168152f35b3461039d57600036600319011261039d5761106d6139fa565b600080546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b3461039d57604036600319011261039d576110c96004356108b6565b602060405160008152f35b3461039d5760a036600319011261039d576110ee3661069a565b506064356001600160401b03811161039d5761110e9036906004016106bc565b5050602060843561111e8161038c565b6040516001600160a01b0390911630148152f35b3461039d57604036600319011261039d576107ac6004356111528161038c565b6024359061115f826108b6565b6111676139fa565b60018060a01b0316600052600560205260406000209063ffffffff60401b82549160401b169063ffffffff60401b1916179055565b8015150361039d57565b3461039d57602036600319011261039d577f57f2a528edf864f533774c287d06a5278e1a4447ed97923b7bbc251fcbd54f6f60206004356111e68161119c565b6111ee6139fa565b151560ff19600b541660ff821617600b55604051908152a1005b3461039d57600036600319011261039d576000546040516001600160a01b039091168152602090f35b3461039d57604036600319011261039d57602060ff61127b6024356004356112588261038c565b6000526003845260406000209060018060a01b0316600052602052604060002090565b54166040519015158152f35b3461039d5760a036600319011261039d576112a13661069a565b6064356084356001600160401b03811161039d576112c39036906004016106bc565b90923033036113f45763ffffffff63fffff9be91356112e1816108b6565b1611156113285761070861130961130284600052600a602052604060002090565b544261371c565b11611317576107ac9261446b565b631a86ecf960e01b60005260046000fd5b826113369392500190614305565b6001600160a01b0392831660008181526005602052604090209093919290911690546113628160601c90565b906001600160a01b038216156105fe5763ffffffff16460361138857506107ac926148f6565b600093508392908390610efe906113d2906113b3906001600160a01b03165b6001600160a01b031690565b946040519283916020830196639277283360e01b885260248401614348565b51925af16113de614360565b506107ac57635f0ad7b760e11b60005260046000fd5b63139f696160e31b60005260046000fd5b3461039d57602036600319011261039d57602061ffff61145463ffffffff60043561142f816108b6565b1663ffffffff908060031c600052600c60205260e06040600020549160051b161c1690565b16604051908152f35b3461039d57600036600319011261039d57602060405160008152f35b3461039d57602036600319011261039d576004356114968161038c565b60018060a01b0316600052600560205260806040600020546040519063ffffffff8116825263ffffffff8160201c16602083015263ffffffff8160401c16604083015260601c6060820152f35b3461039d57604036600319011261039d577fc40a8c1d6db18d083249778a76a84a78429c4fe53001aba75f470c597afaee276040600435611523816108b6565b61ffff61152e610beb565b6115366139fa565b16600c602052631fffffff8260031c166000528260002060e08360051b168154908382821c1863ffffffff16901b18905563ffffffff8351921682526020820152a1005b3461039d57606036600319011261039d576115e160043561159a816108b6565b60243563ffffffff604435926115af84610e5a565b1660005260086020526040600020906000526020526040600020906001600160401b0316600052602052604060002090565b54604051908152602090f35b3461039d57602036600319011261039d576004356001600160401b03811161039d5761161d903690600401610447565b906116266139fa565b61162f82612a73565b9061163d6040519283610cb1565b828252602082019260051b81019036821161039d5780935b828510611665576107ac84613ead565b84356001600160401b03811161039d5782019060608236031261039d576040519161168f83610c5b565b803561169a816108b6565b83526116a860208201610bfc565b60208401526040810135906001600160401b03821161039d57019036601f8301121561039d576020926116e2849336908581359101612a8a565b6040820152815201940193611655565b3461039d57602036600319011261039d5763ffffffff600435611714816108b6565b1660005260016020526020604060002054604051908152f35b3461039d57606036600319011261039d5760043561174a816108b6565b611752610beb565b604435906001600160401b03821161039d576105d092611779610ae29336906004016106bc565b929091612b31565b60c036600319011261039d57600435611799816108b6565b602435906117a68261038c565b6044356001600160401b03811161039d576117c5903690600401610447565b606492919235906117d58261038c565b608435916117e28361038c565b6117ea61048d565b906001600160a01b03811615611a545763ffffffff85169463ffffffff7f00000000000000000000000000000000000000000000000000000000000000001686148015611a47575b610ffe578315611a36576001600160a01b03881660009081526005602052604090209261187161186c611866865460601c90565b956124b0565b613fac565b15611a0257889291906001600160a01b03851660005b8781106119865750509060006118c96118e4935b888c604051986118c38a6118b585858d86602086016128b9565b03601f1981018c528b610cb1565b866127bd565b60405180948192632f1c2cd560e21b83528560048401612476565b0381305afa9687156105f9577f6a0cf129b799c36943cf19ef7755eafb0b597737ba2f970045385de48107886a976119649561194694600092611969575b5061192b6123a6565b348152600060208201526001600160a01b0390931693614030565b506040516001600160a01b0393841698909316969293849384612c0e565b0390a4005b61197f9192503d806000833e6105ea8183610cb1565b9038611922565b90919293945061199781888c612bf9565b3590823b1561039d576040516323b872dd60e01b8152336004820152306024820152604481019290925260008260648183875af19182156105f9576001926119e7575b5001908a94939291611887565b806119f660006119fc93610cb1565b8061060e565b386119da565b9091906001600160a01b0384163303611a2557889260006118c96118e49361189b565b6348f5c3ed60e01b60005260046000fd5b630f59b9ff60e01b60005260046000fd5b5063fffff9be8611611832565b63d721852160e01b60005260046000fd5b3461039d5760006020366003190112611b0a5780600435611a858161038c565b611a8d6139fa565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15611b065760405163ca5eb5e160e01b81526001600160a01b0390921660048301529091908290602490829084905af180156105f9578290611af85780f35b611b0191610cb1565b388180f35b5050fd5b80fd5b3461039d57604036600319011261039d577f69bdfca1ae414a7233840909f9c10a21560d38e0ed4fb50ff50b7b4c29ad96fe600435611b4b8161038c565b60243590611b588261119c565b611b606139fa565b6001600160a01b0316600081815260096020908152604091829020805460ff191660ff9515159586161790558151928352820192909252a1005b3461039d57602036600319011261039d5763ffffffff600435611bbc816108b6565b611bc46139fa565b1663fffff9be811115611c0d576020817fd22acca42bfd0ebef8a1ca8347653f46f782b92b553ba57e0f2294426dfe26ac9263ffffffff196004541617600455604051908152a1005b633df6e48d60e21b60005260046000fd5b3461039d57604036600319011261039d576107ac602435600435611c418261038c565b611c5c6108ac82600052600360205260016040600020015490565b613a6b565b3461039d5760a036600319011261039d57600435611c7e8161038c565b602435611c8a816108b6565b60443591611c978361038c565b60643590611ca4826108b6565b60843592611cb1846108b6565b611cb96138b7565b63ffffffff8116928315611f105763ffffffff8116958615610ffe576001600160a01b038116958615611eff576001600160a01b038516958615611eff57627a120063ffffffff831611611eee574603611eb05763ffffffff7f0000000000000000000000000000000000000000000000000000000000000000168803610ffe57868603611e9f575b6001600160a01b0382166000908152600560205260409020611d67906113a79061053c565b611e8e5784611ded611dfd92611de0611e1796611dbc87611d9d611e679c60018060a01b03166000526006602052604060002090565b80546001600160a01b0319166001600160a01b03909216919091179055565b611dd3611dc76123b5565b63ffffffff909a168a52565b63ffffffff166020890152565b63ffffffff166040870152565b6001600160a01b03166060850152565b6001600160a01b0316600090815260056020526040902090565b8151602080840151604080860151606096870151911b63ffffffff60401b1663ffffffff9094169190921b67ffffffff000000001617919091176001600160601b03199190931b16919091179055565b7f328b68290d8d3a315d25b2476661d7c921ee87029fc767a4916b407e2ee31ede600080a4005b6341ab882d60e01b60005260046000fd5b630232505d60e61b60005260046000fd5b63ffffffff7f0000000000000000000000000000000000000000000000000000000000000000168803611d4257634d30e69360e11b60005260046000fd5b634a11e78360e11b60005260046000fd5b63d92e233d60e01b60005260046000fd5b63057f3fa760e51b60005260046000fd5b3461039d57600036600319011261039d5760206040517f8970ff45bc1804c7a79662cce9df9b0403588be8e486c6f5a410a2814caa892c8152f35b3461039d57604036600319011261039d576004356001600160401b03811161039d57611f8c9036906004016106bc565b602435906001600160401b03821161039d576105d092611fb3610ae29336906004016106bc565b929091612c97565b3461039d57604036600319011261039d576004356001600160401b03811161039d57611feb9036906004016106bc565b602435906001600160401b03821161039d576105d092612012610ae2933690600401610447565b929091612f8a565b3461039d57604036600319011261039d576107ac60043561203a816108b6565b6024356120468161119c565b61204e6139fa565b1561205a573090613a23565b600090613a23565b3461039d57602036600319011261039d5760043561207f8161038c565b60018060a01b03166000526006602052602060018060a01b0360406000205416604051908152f35b3461039d57600036600319011261039d57602060ff600b54166040519015158152f35b3461039d57602036600319011261039d576004356120e78161038c565b6120ef6139fa565b6001600160a01b0316801561214157600080546001600160a01b03198116831782556001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3005b631e4fbdf760e01b600052600060045260246000fd5b60a036600319011261039d5760043561216f8161038c565b6024356001600160401b03811161039d5761218e903690600401610447565b6044356001600160401b03811161039d576121ad903690600401610447565b93606435946121bb8661038c565b6121c36104a3565b9184158015612357575b611a36576001600160a01b0381166000908152600560205260409020805460601c959086156105fe5761220561186c612209926124b0565b1590565b806122fb575b6122ea5761222081888588866132f3565b9061225c600061224161223860045463ffffffff1690565b97848c88612914565b60405180938192632f1c2cd560e21b83528a60048401612476565b0381305afa9586156105f9576105d09a7fed0c24299d2da4e3728deedbf20de24c4ff0e754c89f20b3d2532fe63b43b531976122d7956122a694600092611969575061192b6123a6565b5197426122bd8a600052600a602052604060002090565b556040516001600160a01b039094169693948594856131c3565b0390a36040519081529081906020820190565b634a91ec5f60e01b60005260046000fd5b50604051637347ebb960e01b81526020816004818a5afa9081156105f957600091612328575b501561220f565b61234a915060203d602011612350575b6123428183610cb1565b810190612500565b38612321565b503d612338565b5081156121cd565b3461039d57606036600319011261039d57602061237b3661069a565b63ffffffff813561238b816108b6565b16600052600182528160406000205491013560405191148152f35b60405190610d0b604083610cb1565b60405190610d0b608083610cb1565b60405190610d0b60e083610cb1565b60405190610d0b60c083610cb1565b60405190610d0b60a083610cb1565b6001600160401b038111610c7657601f01601f191660200190565b81601f8201121561039d578051612422816123f1565b926124306040519485610cb1565b8184526020828401011161039d5761244e9160208085019101610a7d565b90565b9060208282031261039d5781516001600160401b03811161039d5761244e920161240c565b60609063ffffffff61244e9493168152600160208201528160408201520190610aa0565b6040513d6000823e3d90fd5b3561244e816108b6565b90604051608081018181106001600160401b03821117610c7657604052606081935463ffffffff8116835263ffffffff8160201c16602084015263ffffffff8160401c166040840152811c910152565b9081602091031261039d575161244e8161119c565b9081602091031261039d575161244e8161038c565b6001600160a01b03166000908152600560205260409020909190612552906124b0565b6124b0565b9163ffffffff612569602085015163ffffffff1690565b16156127b2576125916060612582855163ffffffff1690565b9401516001600160a01b031690565b9260009063ffffffff1646036126dc57506040516331a9108f60e11b815260048101829052906020826024816001600160a01b0388165afa600092816126bb575b506125e35750505050600090600090565b6001600160a01b03821630036125fe57505050503090600190565b602091935b604051637f63c3dd60e01b81526001600160a01b039091166004820152602481019190915267ffffffffffffffff19909216604483015281806064810103817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa6000918161268a575b50612683575090600090565b9160009150565b6126ad91925060203d6020116126b4575b6126a58183610cb1565b810190612515565b9038612677565b503d61269b565b6126d591935060203d6020116126b4576126a58183610cb1565b91386125d2565b906001600160a01b03841680158015612761575b15612702575050505050600090600190565b6040516331a9108f60e11b81526004810183905260209390918490839060249082905afa909181612742575b5061273c5750600093612603565b93612603565b61275a919250843d86116126b4576126a58183610cb1565b903861272e565b50604051635a2d1e0760e11b815260048101839052602081602481855afa9081156105f9578491612793575b506126f0565b6127ac915060203d602011612350576123428183610cb1565b3861278d565b505050600090600190565b929150926127fd9360018060a01b0316600052600560205263ffffffff60406127e8816000206124b0565b94828060208801511691161494015116613b16565b90612806613b7e565b91600361ffff612815856141cf565b160361284b5761244e9192604051916001600160801b03199060801b16602083015260108252612846603083610cb1565b61421b565b61ffff612857846141cf565b633a51740d60e01b6000521660045260246000fd5b81835290916001600160fb1b03831161039d5760209260051b809284830137010190565b6001600160a01b0390911681526000602082015260606040820181905261244e9391019161286c565b6001600160a01b0391821681529116602082015260606040820181905261244e9391019161286c565b634e487b7160e01b600052601160045260246000fd5b63ffffffff1660e0019063ffffffff821161290f57565b6128e2565b61296e9293915060018060a01b031660005260056020526001600160801b0363ffffffff61294560406000206124b0565b51164614806000146129bd576201adb0905b156129b457816206390e5b81871602160116613af6565b90627a12006001600160801b03831611611eee5763ffffffff166060029063ffffffff821691820361290f576129a661244e926128f8565b906129af613b7e565b613b9a565b8161c350612962565b6201b7d890612957565b908060209392818452848401376000828201840152601f01601f1916010190565b61244e94926001600160401b03604060a09463ffffffff8135612a0a816108b6565b168552602081013560208601520135612a2281610e5a565b166040830152606082015281608082015201916129c7565b60349392916bffffffffffffffffffffffff199060601b168152612a68825180936020601485019101610a7d565b019060148201520190565b6001600160401b038111610c765760051b60200190565b929192612a96826123f1565b91612aa46040519384610cb1565b82948184528183011161039d578281602093846000960137010152565b90606e1161039d57602e0190604090565b9060541161039d5760400190601490565b602083610d0b939594956040519684612b05899651809287808a019101610a7d565b8501918483013701016000815203601f198101845283610cb1565b91602061244e9381815201916129c7565b612b639163ffffffff610dcb929694959616600052600260205260406000209061ffff16600052602052604060002090565b805115612bd5578315612bcf576002841015612b9b575050612b97604051928392639a6d49cd60e01b845260048401612b20565b0390fd5b909192612bb1612bac368387612a8a565b613f74565b600081600211611b0a5750600261244e939401906001190191612ae3565b92509050565b50919061244e913691612a8a565b634e487b7160e01b600052603260045260246000fd5b9190811015612c095760051b0190565b612be3565b91602091612c279195949560408552604085019161286c565b6001600160a01b03909416910152565b919082604091031261039d5760208235612c508161038c565b92013590565b919082604091031261039d5760208235612c6f8161038c565b92013561244e8161119c565b60405190612c8a602083610cb1565b6000808352366020840137565b612caa612cc792612cb292959495612ac1565b810190612c37565b936001600160a01b0390911692810190612c56565b612de6578183612cef61254d61244e9560018060a01b03166000526005602052604060002090565b91612cf983613fac565b15612d66576001600160a01b03166000908152600760205260409020610efe9250612d3491612d2791610f49565b546001600160a01b031690565b935b604080516001600160a01b0396871660208201529590931692850192909252606084019190915282906080820190565b505060600151612d80906113a7906001600160a01b031681565b6040516331a9108f60e11b81526004810185905290602090829060249082905afa60009181612dc5575b50612dbb5750610efe600093612d36565b610efe9093612d36565b612ddf91925060203d6020116126b4576126a58183610cb1565b9038612daa565b50505061244e612c7b565b356001600160601b0319811692919060148210612e0c575050565b6001600160601b031960149290920360031b82901b16169150565b90612e3182612a73565b612e3e6040519182610cb1565b8281528092612e4f601f1991612a73565b0190602036910137565b9190811015612c095760051b81013590601e198136030182121561039d5701908135916001600160401b03831161039d57602001823603811361039d579190565b9081606091031261039d578035612eb08161038c565b9160406020830135612c508161038c565b8051821015612c095760209160051b010190565b906020808351928381520192019060005b818110612ef35750505090565b82516001600160a01b0316845260209384019390920191600101612ee6565b906020808351928381520192019060005b818110612f305750505090565b8251845260209384019390920191600101612f23565b92612f6e61244e9593612f7c9360018060a01b03168652608060208701526080860190612ed5565b908482036040860152612ed5565b916060818403910152612f12565b612fb561254d611dfd612faf612fa9612fc3966060969a99989a612ad2565b90612df1565b60601c90565b01516001600160a01b031690565b612fcc82612e27565b91612fd681612e27565b94612fe082612e27565b91600091825b8281106130cb57505050815181106130125750610efe9061244e93949560405195869460208601612f46565b929061301d84612e27565b9361302781612e27565b9161303182612e27565b9360005b83811061305b575050505061244e9394955090610efe9160405195869460208601612f46565b806130af6130a561307e838e6130a08e6130918461308b61307e60019c8e612ec1565b516001600160a01b031690565b92612ec1565b6001600160a01b039091169052565b612ec1565b6130918389612ec1565b6130b98185612ec1565b516130c48289612ec1565b5201613035565b6130d6818484612e59565b9050156131bb576131308161311d8b613091838a61310d6131036130fb848d8d612e59565b810190612e9a565b9291989093612ec1565b526001600160a01b031692612ec1565b6001600160a01b0316613091838a612ec1565b61313d61307e8289612ec1565b61314d6113a761307e848d612ec1565b6001600160a01b0390911603613168575b6001905b01612fe6565b92600180916131778688612ec1565b516131828289612ec1565b5261319d61319361307e888c612ec1565b613091838c612ec1565b6131b28b6130918361308b61307e8b85612ec1565b0193905061315e565b600190613162565b949391949290928560408201604083525260608101936000965b8088106131f957505061244e949550602081850391015261286c565b909460208060019263ffffffff8935613211816108b6565b168152019601970196906131dd565b908160011b918083046002149015171561290f57565b8181029291811591840414171561290f57565b9061325382612a73565b6132606040519182610cb1565b8281528092613271601f1991612a73565b019060005b82811061328257505050565b60209060405161329181610c7b565b60008152600083820152600060408201526000606082015260006080820152600060a0820152606060c082015282828501015201613276565b906001820180921161290f57565b906023820180921161290f57565b9190820180921161290f57565b9291926133086133038587613236565b613249565b9360006001600160401b034216967f0000000000000000000000000000000000000000000000000000000000000000915b8181106133b157505050505050509061244e9161339f6133576123d3565b600281529263ffffffff7f0000000000000000000000000000000000000000000000000000000000000000166020850152600060408501526001600160401b03166060840152565b600060808301523060a083015261412d565b60005b8481106133c45750600101613339565b61340a6133e66133dd6133d884898c612bf9565b6124a6565b63ffffffff1690565b63ffffffff908060031c600052600c60205260e06040600020549160051b161c1690565b63ffffffff811615610ffe578484613421856132ca565b61342b8286613236565b613434916132e6565b61ffff1692888c878d88613449818684612bf9565b613452906124a6565b9461345c92612bf9565b613465906124a6565b61346e906136d8565b6001600160a01b03169461348192612bf9565b604051631a98288d60e11b60208201526001600160a01b038d1660248201529035604482015267ffffffffffffffff199490941660648086019190915284526134cb608485610cb1565b6134d36123c4565b61ffff909516855263ffffffff166020850152600060408501526001600160401b038e16606085015261ffff1660808401526001600160a01b031660a083015260c0820152816135238785613236565b9061352d916132e6565b90613538828c612ec1565b52613543908a612ec1565b506001016133b4565b6040519061355982610c96565b60006020838281520152565b919082604091031261039d5760405161357d81610c96565b6020808294805184520151910152565b9060408282031261039d5761244e91613565565b906020909392936040835263ffffffff815116604084015281810151606084015260806135f56135df604084015160a08488015260e0870190610aa0565b6060840151868203603f190160a0880152610aa0565b910151151560c08401526001600160a01b03909416910152565b61366f9260409261361e61354c565b50613628836136d8565b61363f6136336123e2565b63ffffffff9095168552565b602084015283830152606082015260006080820152815180938192631bb8518b60e31b83523090600484016135a1565b03817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa9081156105f9576000916136af575090565b61244e915060403d6040116136d1575b6136c98183610cb1565b81019061358d565b503d6136bf565b63ffffffff168060005260016020526040600020549081156136f8575090565b63f6ff4fb760e01b60005260045260246000fd5b61c34f1981019190821161290f57565b9190820391821161290f57565b3561244e81610e5a565b6040906001600160401b0361244e94931681528160208201520190610aa0565b93929192613763600b5460ff1690565b9081613893575b5061388257610efe613793926040519485936304c98a8b60e51b602086015287602486016129e8565b6137a6816137a05a61370c565b30613ca4565b9190156137b257505050565b63ffffffff7fd191660d5fb7fa40de3038f810fa899670f44a26d29f0609702b778de1c4e5f6916040516137f181610efe602082019446903087612a3a565b51902061387d61386e61386861381f613809896124a6565b63ffffffff166000526008602052604060002090565b976138396020820135809a90600052602052604060002090565b94613862604083019661384b88613729565b6001600160401b0316600052602052604060002090565b556124a6565b92613729565b94604051938493169583613733565b0390a3565b6341c8302160e11b60005260046000fd5b6001600160a01b031660009081526009602052604090205460ff161590503861376a565b3360009081527f460e1c17541eb4600da639136d22ecdece50dfd5504d40fe2d419370e887d378602052604090205460ff16156138f057565b63e2517d3f60e01b600052336004527f8970ff45bc1804c7a79662cce9df9b0403588be8e486c6f5a410a2814caa892c60245260446000fd5b600081815260036020908152604080832033845290915290205460ff161561394e5750565b63e2517d3f60e01b6000523360045260245260446000fd5b60008181526003602090815260408083206001600160a01b038616845290915290205460ff166139f35760008181526003602090815260408083206001600160a01b03861684529091529020805460ff1916600117905533916001600160a01b0316907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d600080a4600190565b5050600090565b6000546001600160a01b03163303613a0e57565b63118cdaa760e01b6000523360045260246000fd5b7f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b9163ffffffff604092169081600052600160205280836000205582519182526020820152a1565b60008181526003602090815260408083206001600160a01b038616845290915290205460ff16156139f35760008181526003602090815260408083206001600160a01b03861684529091529020805460ff1916905533916001600160a01b0316907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b600080a4600190565b906001600160801b03809116911601906001600160801b03821161290f57565b916001600160801b03613b4e948193948180613b73575b15613b6957905b15613b645762031c870181165b16026201adb00116613af6565b90627a12006001600160801b03831611611eee57565b613b41565b5061c35090613b34565b508281161515613b2d565b604051600360f01b60208201526002815261244e602282610cb1565b9091600361ffff613baa846141cf565b1603613c985760405160809390931b6fffffffffffffffffffffffffffffffff1916602084015260e01b6001600160e01b031916603083015260148252613bf2603483610cb1565b600361ffff613c00836141cf565b1603613c8c57600161ffff613c1584516148cd565b16019161ffff831161290f5761244e9160206004926040519583613c428895518092868089019101610a7d565b840190600160f81b8483015261ffff60f01b9060f01b166021820152600560f81b6023820152613c7b8251809385602485019101610a7d565b01010301601f198101835282610cb1565b61285761ffff916141cf565b61ffff612857836141cf565b929190600091829182613cb760046123f1565b96613cc56040519889610cb1565b60048852601f19613cd660046123f1565b013660208a013760208451940192f13d60048111613cfd575b8084526000602085013e9190565b506004613cef565b601f8211613d1257505050565b6000526020600020906020601f840160051c83019310613d4d575b601f0160051c01905b818110613d41575050565b60008155600101613d36565b9091508190613d2d565b91909182516001600160401b038111610c7657613d7e81613d788454610c0b565b84613d05565b6020601f8211600114613dbf578190613db0939495600092613db4575b50508160011b916000199060031b1c19161790565b9055565b015190503880613d9b565b601f19821690613dd484600052602060002090565b9160005b818110613e1057509583600195969710613df7575b505050811b019055565b015160001960f88460031b161c19169055388080613ded565b9192602060018192868b015181550194019201613dd8565b602081016020825282518091526040820191602060408360051b8301019401926000915b838310613e5b57505050505090565b9091929394602080613e9e600193603f19868203018752606060408b5163ffffffff815116845261ffff8682015116868501520151918160408201520190610aa0565b97019301930191939290613e4c565b60005b8151811015613f3d5780613ed36040613ecb60019486612ec1565b510151613f74565b613f376040613ee28386612ec1565b51015163ffffffff613ef48487612ec1565b5151166000526002602052613f326040600020613f206020613f16878a612ec1565b51015161ffff1690565b61ffff16600052602052604060002090565b613d57565b01613eb0565b50613f6f7fbe4864a8e820971c0247f5992e2da559595f7bf076a21cb5928d443d2a13b6749160405191829182613e28565b0390a1565b600361ffff60028301511603613f875750565b604051639a6d49cd60e01b815260206004820152908190612b97906024830190610aa0565b63ffffffff815116156105fe5763ffffffff905116461490565b60405190613fd382610c5b565b8160008152600060208201526040613fe961354c565b910152565b9060808282031261039d5761402890604080519361400b85610c5b565b80518552602081015161401d81610e5a565b602086015201613565565b604082015290565b614099608094926140b59694614044613fc6565b50602061405186516146a8565b95019182518061411e575b50614066856136d8565b92511515926140826140766123e2565b63ffffffff9097168752565b602086015260408501526060840152151585830152565b6040518095819482936302637a4560e41b8452600484016135a1565b03917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af19081156105f9576000916140f5575090565b61244e915060803d608011614117575b61410f8183610cb1565b810190613fee565b503d614105565b614127906146c7565b3861405c565b91909161413a81516148cd565b604051600160f01b60208201526000602282015260f09190911b6001600160f01b031916602482015260068152614172602682610cb1565b916000925b825184101561419f576141976001916141908686612ec1565b5190614e82565b930192614177565b92509290508163ffffffff6141bb602084015163ffffffff1690565b166141c557505090565b61244e92506147d6565b60028151106141df576002015190565b60405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b6044820152606490fd5b600361ffff614229836141cf565b1603613c8c57600161ffff61423e84516148cd565b16019161ffff831161290f5761244e916020600492604051958361426b8895518092868089019101610a7d565b600160f81b90850184810182905260f09290921b6001600160f01b03191660218301526023820152815191613c7b90839060248401908601610a7d565b9080601f8301121561039d5781356142bf81612a73565b926142cd6040519485610cb1565b81845260208085019260051b82010192831161039d57602001905b8282106142f55750505090565b81358152602091820191016142e8565b9160608383031261039d57823561431b8161038c565b92602081013561432a8161038c565b9260408201356001600160401b03811161039d5761244e92016142a8565b90612c27602091949394604084526040840190612f12565b3d1561438b573d90614371826123f1565b9161437f6040519384610cb1565b82523d6000602084013e565b606090565b9080601f8301121561039d5781356143a781612a73565b926143b56040519485610cb1565b81845260208085019260051b82010192831161039d57602001905b8282106143dd5750505090565b6020809183356143ec8161038c565b8152019101906143d0565b9060808282031261039d57813561440d8161038c565b9260208301356001600160401b03811161039d578261442d918501614390565b9260408101356001600160401b03811161039d578361444d918301614390565b9260608201356001600160401b03811161039d5761244e92016142a8565b61447a919392938101906143f7565b6001600160a01b03909316600081815260066020526040902091929161449f90612d27565b916144c261186c61254d8560018060a01b03166000526005602052604060002090565b156144d4575050610d0b939450614ad5565b91509360005b845181101561465b576000806144f361307e8487612ec1565b61450061307e8589612ec1565b9061450b858a612ec1565b51906001600160a01b03811615841461458457506040516340c10f1960e01b602082019081526001600160a01b03909316602482015260448101919091526145568160648101610efe565b5190828a5af1614564614360565b5015614574576001905b016144da565b62ec6f7b60e31b60005260046000fd5b916001600160a01b0381161584146145ee5750604051630852cd8d60e31b6020820190815260248201929092529091506145c18160448101610efe565b5190828a5af16145cf614360565b50156145dd5760019061456e565b631bc5aabf60e21b60005260046000fd5b6040516323b872dd60e01b602082019081526001600160a01b039485166024830152939091166044820152606481019190915261462e8160848101610efe565b5190828a5af161463c614360565b501561464a5760019061456e565b6312171d8360e31b60005260046000fd5b50949392505050803b1561039d5760405163163b5cc360e31b815260048101929092526000908290602490829084905af180156105f9576146995750565b806119f66000610d0b93610cb1565b8034036146b25790565b6304fb820960e51b6000523460045260246000fd5b60405163393f876560e21b81527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690602081600481855afa9081156105f9576000916147b7575b506001600160a01b03169182156147a6576040516323b872dd60e01b60208281019182523360248401526001600160a01b03909416604483015260648201929092526000919061476a8160848101610efe565b519082855af11561249a576000513d61479d5750803b155b6147895750565b635274afe760e01b60005260045260246000fd5b60011415614782565b6329b99a9560e11b60005260046000fd5b6147d0915060203d6020116126b4576126a58183610cb1565b38614717565b61244e9060276020936148be60ff825116916148aa63ffffffff888301511691604081015115156001600160401b036060830151169061ffff6080840151169260a0600180821b0391015116946040519b8c9a61483c828d019182815194859201610a7d565b600160f81b9101908152600160f01b600182015260f898891b6001600160f81b031916600382015260e09190911b6001600160e01b031916600482015290151590961b600887015260c01b6001600160c01b031916600986015260f01b6001600160f01b0319166011850152565b60601b6001600160601b0319166013830152565b0103601f198101835282610cb1565b61ffff81116148dd5761ffff1690565b6306dfcc6560e41b600052601060045260245260446000fd5b60005b8351811015614985576001600160a01b0382166149168286612ec1565b5190803b1561039d576040516323b872dd60e01b81523060048201526001600160a01b038616602482015260448101929092526000908290606490829084905af180156105f95761496b575b506001016148f9565b8061497860008093610cb1565b80031261039d5738614962565b50610d0b929150614f30565b9061499b82612a73565b6149a86040519182610cb1565b82815280926149b9601f1991612a73565b019060005b8281106149ca57505050565b8060606020809385010152016149be565b60208183031261039d578051906001600160401b03821161039d57019080601f8301121561039d578151614a0e81612a73565b92614a1c6040519485610cb1565b81845260208085019260051b8201019183831161039d5760208201905b838210614a4857505050505090565b81516001600160401b03811161039d57602091614a6a8784809488010161240c565b815201910190614a39565b602081016020825282518091526040820191602060408360051b8301019401926000915b838310614aa857505050505090565b9091929394602080614ac6600193603f198682030187528951610aa0565b97019301930191939290614a99565b909291614aea614ae58251613220565b614991565b600094855b8351811015614ce157614b0561307e8284612ec1565b614b0f8286612ec1565b5190614b34612d2783610f498a60018060a01b03166000526007602052604060002090565b6040516331a9108f60e11b8152600481018490526020816024816001600160a01b038d165afa9081156105f957600091614cc3575b50306001600160a01b0390911603614cb2576001600160a01b038116614c41575b506001600160a01b038116614ba4575b5050600101614aef565b60405163b18e2bbb60e01b60208201526001600160a01b038083166024830152881660448201526064810183905264ffffffffff6084820152600160a482018190529299929392614c3a9291611d9d918691614c038160c48101610efe565b614c0d828b612ec1565b52614c18818a612ec1565b506001600160a01b038b16600090815260076020526040902091019b90610f49565b9038614b9a565b60405163b18e2bbb60e01b60208201526001600160a01b03918216602482015290881660448201526064810183905264ffffffffff6084820152600060a48201529098600191614c948160c48101610efe565b614c9e8288612ec1565b52614ca98187612ec1565b50019738614b8a565b6349e27cff60e01b60005260046000fd5b614cdb915060203d81116126b4576126a58183610cb1565b38614b69565b50509293915050614cf181614991565b9160005b828110614d80575050614d055750565b6000614d259160405180938192631592ca1b60e31b835260048301614a75565b0381837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af180156105f957614d615750565b614d7d903d806000833e614d758183610cb1565b8101906149db565b50565b80614d8d60019284612ec1565b51614d988287612ec1565b52614da38186612ec1565b5001614cf5565b602090614dc2600b9694959382815194859201610a7d565b600160f81b910190815260f093841b6001600160f01b03199081166001830152600160f01b60038301529190931b16600583015260e01b6001600160e01b03191660078201520190565b602090614e27601f9897959396949682815194859201610a7d565b94151560f81b940193845260c01b6001600160c01b031916600184015260f01b6001600160f01b031916600983015260601b6001600160601b031916600b820152815191614e7d90839085840190602001610a7d565b010190565b9061244e90610efe614e96825161ffff1690565b91614ede60c0820195614ed0614eb5614eb08951516132d8565b6148cd565b602085015163ffffffff169060405197889460208601614daa565b03601f198101855284610cb1565b6040810151151594614efa60608301516001600160401b031690565b91614f1e60a0614f0f608084015161ffff1690565b9201516001600160a01b031690565b91519260405197889660208801614e0c565b919091614f3d8351614991565b600091825b855181101561503d57614f558187612ec1565b5193614f7a612d2786610f498660018060a01b03166000526007602052604060002090565b6001600160a01b038116156150325760405163b18e2bbb60e01b60208201526001600160a01b03918216602482015290841660448201526064810186905264ffffffffff6084820152600060a48201526001929161502c9161501c918591614fe58160c48101610efe565b614fef868a612ec1565b52614ffa8589612ec1565b506001600160a01b038716600090815260076020526040902091019790610f49565b80546001600160a01b0319169055565b01614f42565b50935060019061502c565b505091925061504b81614991565b9160005b82811061505f575050614d055750565b8061506c60019284612ec1565b516150778287612ec1565b526150828186612ec1565b500161504f56fea2646970667358221220e40b6d1cbc769734a9e93e86e73c5e53f52e0ab913b57d4d7ec28c3efef89db364736f6c634300081d00332f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d460e1c17541eb4600da639136d22ecdece50dfd5504d40fe2d419370e887d3783617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff000000000000000000000000000000000000506aa8bc5da44f9b3329b8c6f7e00000000000000000000000005454757e592aedf88b9786313e878ed65b96367700000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000447e69651d841bd8d104bed4930000000000000000000000000000000000007129af73c46c9f01a3fb4ff61a020000000000000000000000005454757e592aedf88b9786313e878ed65b963677
Deployed Bytecode
0x6080604052600436101561001257600080fd5b60003560e01c806301a0de051461038757806301ffc9a71461038257806304bd49a51461037d578063066d591014610378578063108dcbdd1461037357806313137d651461036e57806317442b70146103695780631d56672114610364578063248a9ca31461035f5780632f2ff15d1461035a5780633400288b146103555780633530511a1461035057806336568abe1461034b57806336b1dd211461034657806337cb6736146103415780634202fce11461033c57806345248a3714610337578063461572f91461033257806347c1b3171461032d5780635535d461146103285780635e280f11146103235780636a4d86721461031e5780636eaa6904146103195780636fe87dba14610314578063715018a61461030f5780637d25a05e1461030a57806382413eac14610305578063864c651514610300578063881ae9f8146102fb5780638da5cb5b146102f657806391d14854146102f157806399315160146102ec578063a0238f3e146102e7578063a217fddf146102e2578063a34ac81b146102dd578063ade7142d146102d8578063b33b522d146102d3578063b98bd070146102ce578063bb0b6a53146102c9578063bc70b354146102c4578063c9df8167146102bf578063ca5eb5e1146102ba578063cfac96ce146102b5578063d1e1d0cc146102b0578063d547741f146102ab578063da383b97146102a6578063e052778a146102a1578063e60c287c1461029c578063eba1cf0814610297578063f0a9e48114610292578063f17488351461028d578063f1c418ee14610288578063f2fde38b14610283578063fe084c8f1461027e5763ff7bd03d1461027957600080fd5b61235f565b612157565b6120ca565b6120a7565b612062565b61201a565b611fbb565b611f5c565b611f21565b611c61565b611c1e565b611b9a565b611b0d565b611a65565b611781565b61172d565b6116f2565b6115ed565b61157a565b6114e3565b611479565b61145d565b611405565b611287565b611231565b611208565b6111a6565b611132565b6110d4565b6110ad565b611054565b61100f565b610e6b565b610e15565b610dd0565b610d76565b610b8b565b610b67565b610af6565b610ac5565b6109df565b61099a565b610950565b6108f5565b6108c4565b61086e565b610839565b61080d565b6107eb565b6106e9565b61065a565b610619565b6104b9565b6103f1565b6103a2565b6001600160a01b0381160361039d57565b600080fd5b3461039d57604036600319011261039d576004356103bf8161038c565b6001600160a01b0390811660009081526007602090815260408083206024358452825291829020549151919092168152f35b3461039d57602036600319011261039d5760043563ffffffff60e01b811680910361039d57602090637965db0b60e01b8114908115610436575b506040519015158152f35b6301ffc9a760e01b1490503861042b565b9181601f8401121561039d578235916001600160401b03831161039d576020808501948460051b01011161039d57565b606435906001600160801b038216820361039d57565b60a435906001600160801b038216820361039d57565b608435906001600160801b038216820361039d57565b3461039d57608036600319011261039d576004356104d68161038c565b6024356001600160401b03811161039d576104f5903690600401610447565b91906044356001600160401b03811161039d57610516903690600401610447565b9361051f610477565b6001600160a01b0385166000908152600560205260409020610543905b5460601c90565b916001600160a01b038316156105fe5761056881866105999960009761057e976132f3565b9461057860045463ffffffff1690565b96612914565b60405180958192632f1c2cd560e21b83528660048401612476565b0381305afa9182156105f9576105b7936000936105d4575b5061360f565b8051602091820151604080519283529282015290819081015b0390f35b6105f29193503d806000833e6105ea8183610cb1565b810190612451565b91386105b1565b61249a565b622dc1c960e71b60005260046000fd5b600091031261039d57565b3461039d57600036600319011261039d57602060405163ffffffff7f0000000000000000000000000000000000000000000000000000000000007668168152f35b3461039d57602036600319011261039d576004356106778161038c565b60018060a01b03166000526005602052602060406000205460601c604051908152f35b606090600319011261039d57600490565b606090606319011261039d57606490565b9181601f8401121561039d578235916001600160401b03831161039d576020838186019501011161039d57565b60e036600319011261039d576106fe3661069a565b6064356084356001600160401b03811161039d576107209036906004016106bc565b9060a4359261072e8461038c565b60c4356001600160401b03811161039d5761074d9036906004016106bc565b5050337f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b0316036107d65784359461078b866108b6565b610794866136d8565b9560208201358097036107ae57506107ac9550613753565b005b63ffffffff816107be89936108b6565b63309afaf360e21b6000521660045260245260446000fd5b6391ac5e4f60e01b6000523360045260246000fd5b3461039d57600036600319011261039d57604080516001815260026020820152f35b3461039d57602036600319011261039d57600435600052600a6020526020604060002054604051908152f35b3461039d57602036600319011261039d576020610866600435600052600360205260016040600020015490565b604051908152f35b3461039d57604036600319011261039d576107ac6024356004356108918261038c565b6108b16108ac82600052600360205260016040600020015490565b613929565b613966565b63ffffffff81160361039d57565b3461039d57604036600319011261039d576107ac6004356108e4816108b6565b602435906108f06139fa565b613a23565b3461039d57606036600319011261039d576004356109128161038c565b60443560243567ffffffffffffffff198216820361039d576109339261252a565b604080516001600160a01b03939093168352901515602083015290f35b3461039d57604036600319011261039d576004356024356109708161038c565b336001600160a01b03821603610989576107ac91613a6b565b63334bd91960e11b60005260046000fd5b3461039d57600036600319011261039d576040517f0000000000000000000000000000000000007129af73c46c9f01a3fb4ff61a026001600160a01b03168152602090f35b3461039d57602036600319011261039d576004356109fc8161038c565b60018060a01b03166000526009602052602060ff604060002054166040519015158152f35b608060031982011261039d57600435610a39816108b6565b91602435610a468161038c565b91604435906001600160401b03821161039d57610a6591600401610447565b90916064356001600160801b038116810361039d5790565b60005b838110610a905750506000910152565b8181015183820152602001610a80565b90602091610ab981518092818552858086019101610a7d565b601f01601f1916010190565b3461039d576105d0610ae2610ad936610a21565b939290926127bd565b604051918291602083526020830190610aa0565b3461039d57610b0436610a21565b6001600160a01b0380851660009081526005602052604090209195949391610b2b9061053c565b16156105fe576105999460009261057e9260405195610b6187610b5385858560208501612890565b03601f198101895288610cb1565b876127bd565b3461039d57600036600319011261039d57602063ffffffff60045416604051908152f35b3461039d57606036600319011261039d57600435610ba88161038c565b6024356001600160401b03811161039d57610bc7903690600401610447565b909190604435906001600160801b038216820361039d576105d093610ae293612914565b6024359061ffff8216820361039d57565b359061ffff8216820361039d57565b90600182811c92168015610c3b575b6020831014610c2557565b634e487b7160e01b600052602260045260246000fd5b91607f1691610c1a565b634e487b7160e01b600052604160045260246000fd5b606081019081106001600160401b03821117610c7657604052565b610c45565b60e081019081106001600160401b03821117610c7657604052565b604081019081106001600160401b03821117610c7657604052565b90601f801991011681019081106001600160401b03821117610c7657604052565b9060405191826000825492610ce684610c0b565b8084529360018116908115610d545750600114610d0d575b50610d0b92500383610cb1565b565b90506000929192526020600020906000915b818310610d38575050906020610d0b9282010138610cfe565b6020919350806001915483858901015201910190918492610d1f565b905060209250610d0b94915060ff191682840152151560051b82010138610cfe565b3461039d57604036600319011261039d576105d0610ae2610dcb600435610d9c816108b6565b63ffffffff610da9610beb565b9116600052600260205260406000209061ffff16600052602052604060002090565b610cd2565b3461039d57600036600319011261039d576040517f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b03168152602090f35b3461039d57600036600319011261039d576040517f00000000000000000000000000000000000000447e69651d841bd8d104bed4936001600160a01b03168152602090f35b6001600160401b0381160361039d57565b3461039d5761010036600319011261039d57600435610e89816108b6565b60243590604435610e9981610e5a565b610ea2366106ab565b9160c43560e4356001600160401b03811161039d57610ec59036906004016106bc565b909463ffffffff84169563fffff9be8711610ffe57610f0c92610efe916040519586946304c98a8b60e51b6020870152602486016129e8565b03601f198101835282610cb1565b6040516020810190610f2481610efe46863087612a3a565b519020610f7084610f5888610f498763ffffffff166000526008602052604060002090565b90600052602052604060002090565b906001600160401b0316600052602052604060002090565b5403610fed576000610f9d84610f5888610f49610fa59763ffffffff166000526008602052604060002090565b555a30613ca4565b9015610fe557506040516001600160401b039190911681527f49a5bb7337668613a742dc30346f29d11f0b4d4a2c0745a08afccc9bb6cea3d090602090a3005b805190602001fd5b63a84ab60d60e01b60005260046000fd5b634d30e69360e11b60005260046000fd5b3461039d57600036600319011261039d5760206040516001600160401b03197f502693d518cccccc945699ac6b0be7c02aef951c921558ec0000000000000000168152f35b3461039d57600036600319011261039d5761106d6139fa565b600080546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b3461039d57604036600319011261039d576110c96004356108b6565b602060405160008152f35b3461039d5760a036600319011261039d576110ee3661069a565b506064356001600160401b03811161039d5761110e9036906004016106bc565b5050602060843561111e8161038c565b6040516001600160a01b0390911630148152f35b3461039d57604036600319011261039d576107ac6004356111528161038c565b6024359061115f826108b6565b6111676139fa565b60018060a01b0316600052600560205260406000209063ffffffff60401b82549160401b169063ffffffff60401b1916179055565b8015150361039d57565b3461039d57602036600319011261039d577f57f2a528edf864f533774c287d06a5278e1a4447ed97923b7bbc251fcbd54f6f60206004356111e68161119c565b6111ee6139fa565b151560ff19600b541660ff821617600b55604051908152a1005b3461039d57600036600319011261039d576000546040516001600160a01b039091168152602090f35b3461039d57604036600319011261039d57602060ff61127b6024356004356112588261038c565b6000526003845260406000209060018060a01b0316600052602052604060002090565b54166040519015158152f35b3461039d5760a036600319011261039d576112a13661069a565b6064356084356001600160401b03811161039d576112c39036906004016106bc565b90923033036113f45763ffffffff63fffff9be91356112e1816108b6565b1611156113285761070861130961130284600052600a602052604060002090565b544261371c565b11611317576107ac9261446b565b631a86ecf960e01b60005260046000fd5b826113369392500190614305565b6001600160a01b0392831660008181526005602052604090209093919290911690546113628160601c90565b906001600160a01b038216156105fe5763ffffffff16460361138857506107ac926148f6565b600093508392908390610efe906113d2906113b3906001600160a01b03165b6001600160a01b031690565b946040519283916020830196639277283360e01b885260248401614348565b51925af16113de614360565b506107ac57635f0ad7b760e11b60005260046000fd5b63139f696160e31b60005260046000fd5b3461039d57602036600319011261039d57602061ffff61145463ffffffff60043561142f816108b6565b1663ffffffff908060031c600052600c60205260e06040600020549160051b161c1690565b16604051908152f35b3461039d57600036600319011261039d57602060405160008152f35b3461039d57602036600319011261039d576004356114968161038c565b60018060a01b0316600052600560205260806040600020546040519063ffffffff8116825263ffffffff8160201c16602083015263ffffffff8160401c16604083015260601c6060820152f35b3461039d57604036600319011261039d577fc40a8c1d6db18d083249778a76a84a78429c4fe53001aba75f470c597afaee276040600435611523816108b6565b61ffff61152e610beb565b6115366139fa565b16600c602052631fffffff8260031c166000528260002060e08360051b168154908382821c1863ffffffff16901b18905563ffffffff8351921682526020820152a1005b3461039d57606036600319011261039d576115e160043561159a816108b6565b60243563ffffffff604435926115af84610e5a565b1660005260086020526040600020906000526020526040600020906001600160401b0316600052602052604060002090565b54604051908152602090f35b3461039d57602036600319011261039d576004356001600160401b03811161039d5761161d903690600401610447565b906116266139fa565b61162f82612a73565b9061163d6040519283610cb1565b828252602082019260051b81019036821161039d5780935b828510611665576107ac84613ead565b84356001600160401b03811161039d5782019060608236031261039d576040519161168f83610c5b565b803561169a816108b6565b83526116a860208201610bfc565b60208401526040810135906001600160401b03821161039d57019036601f8301121561039d576020926116e2849336908581359101612a8a565b6040820152815201940193611655565b3461039d57602036600319011261039d5763ffffffff600435611714816108b6565b1660005260016020526020604060002054604051908152f35b3461039d57606036600319011261039d5760043561174a816108b6565b611752610beb565b604435906001600160401b03821161039d576105d092611779610ae29336906004016106bc565b929091612b31565b60c036600319011261039d57600435611799816108b6565b602435906117a68261038c565b6044356001600160401b03811161039d576117c5903690600401610447565b606492919235906117d58261038c565b608435916117e28361038c565b6117ea61048d565b906001600160a01b03811615611a545763ffffffff85169463ffffffff7f00000000000000000000000000000000000000000000000000000000000076681686148015611a47575b610ffe578315611a36576001600160a01b03881660009081526005602052604090209261187161186c611866865460601c90565b956124b0565b613fac565b15611a0257889291906001600160a01b03851660005b8781106119865750509060006118c96118e4935b888c604051986118c38a6118b585858d86602086016128b9565b03601f1981018c528b610cb1565b866127bd565b60405180948192632f1c2cd560e21b83528560048401612476565b0381305afa9687156105f9577f6a0cf129b799c36943cf19ef7755eafb0b597737ba2f970045385de48107886a976119649561194694600092611969575b5061192b6123a6565b348152600060208201526001600160a01b0390931693614030565b506040516001600160a01b0393841698909316969293849384612c0e565b0390a4005b61197f9192503d806000833e6105ea8183610cb1565b9038611922565b90919293945061199781888c612bf9565b3590823b1561039d576040516323b872dd60e01b8152336004820152306024820152604481019290925260008260648183875af19182156105f9576001926119e7575b5001908a94939291611887565b806119f660006119fc93610cb1565b8061060e565b386119da565b9091906001600160a01b0384163303611a2557889260006118c96118e49361189b565b6348f5c3ed60e01b60005260046000fd5b630f59b9ff60e01b60005260046000fd5b5063fffff9be8611611832565b63d721852160e01b60005260046000fd5b3461039d5760006020366003190112611b0a5780600435611a858161038c565b611a8d6139fa565b7f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b0316803b15611b065760405163ca5eb5e160e01b81526001600160a01b0390921660048301529091908290602490829084905af180156105f9578290611af85780f35b611b0191610cb1565b388180f35b5050fd5b80fd5b3461039d57604036600319011261039d577f69bdfca1ae414a7233840909f9c10a21560d38e0ed4fb50ff50b7b4c29ad96fe600435611b4b8161038c565b60243590611b588261119c565b611b606139fa565b6001600160a01b0316600081815260096020908152604091829020805460ff191660ff9515159586161790558151928352820192909252a1005b3461039d57602036600319011261039d5763ffffffff600435611bbc816108b6565b611bc46139fa565b1663fffff9be811115611c0d576020817fd22acca42bfd0ebef8a1ca8347653f46f782b92b553ba57e0f2294426dfe26ac9263ffffffff196004541617600455604051908152a1005b633df6e48d60e21b60005260046000fd5b3461039d57604036600319011261039d576107ac602435600435611c418261038c565b611c5c6108ac82600052600360205260016040600020015490565b613a6b565b3461039d5760a036600319011261039d57600435611c7e8161038c565b602435611c8a816108b6565b60443591611c978361038c565b60643590611ca4826108b6565b60843592611cb1846108b6565b611cb96138b7565b63ffffffff8116928315611f105763ffffffff8116958615610ffe576001600160a01b038116958615611eff576001600160a01b038516958615611eff57627a120063ffffffff831611611eee574603611eb05763ffffffff7f0000000000000000000000000000000000000000000000000000000000007668168803610ffe57868603611e9f575b6001600160a01b0382166000908152600560205260409020611d67906113a79061053c565b611e8e5784611ded611dfd92611de0611e1796611dbc87611d9d611e679c60018060a01b03166000526006602052604060002090565b80546001600160a01b0319166001600160a01b03909216919091179055565b611dd3611dc76123b5565b63ffffffff909a168a52565b63ffffffff166020890152565b63ffffffff166040870152565b6001600160a01b03166060850152565b6001600160a01b0316600090815260056020526040902090565b8151602080840151604080860151606096870151911b63ffffffff60401b1663ffffffff9094169190921b67ffffffff000000001617919091176001600160601b03199190931b16919091179055565b7f328b68290d8d3a315d25b2476661d7c921ee87029fc767a4916b407e2ee31ede600080a4005b6341ab882d60e01b60005260046000fd5b630232505d60e61b60005260046000fd5b63ffffffff7f0000000000000000000000000000000000000000000000000000000000007668168803611d4257634d30e69360e11b60005260046000fd5b634a11e78360e11b60005260046000fd5b63d92e233d60e01b60005260046000fd5b63057f3fa760e51b60005260046000fd5b3461039d57600036600319011261039d5760206040517f8970ff45bc1804c7a79662cce9df9b0403588be8e486c6f5a410a2814caa892c8152f35b3461039d57604036600319011261039d576004356001600160401b03811161039d57611f8c9036906004016106bc565b602435906001600160401b03821161039d576105d092611fb3610ae29336906004016106bc565b929091612c97565b3461039d57604036600319011261039d576004356001600160401b03811161039d57611feb9036906004016106bc565b602435906001600160401b03821161039d576105d092612012610ae2933690600401610447565b929091612f8a565b3461039d57604036600319011261039d576107ac60043561203a816108b6565b6024356120468161119c565b61204e6139fa565b1561205a573090613a23565b600090613a23565b3461039d57602036600319011261039d5760043561207f8161038c565b60018060a01b03166000526006602052602060018060a01b0360406000205416604051908152f35b3461039d57600036600319011261039d57602060ff600b54166040519015158152f35b3461039d57602036600319011261039d576004356120e78161038c565b6120ef6139fa565b6001600160a01b0316801561214157600080546001600160a01b03198116831782556001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3005b631e4fbdf760e01b600052600060045260246000fd5b60a036600319011261039d5760043561216f8161038c565b6024356001600160401b03811161039d5761218e903690600401610447565b6044356001600160401b03811161039d576121ad903690600401610447565b93606435946121bb8661038c565b6121c36104a3565b9184158015612357575b611a36576001600160a01b0381166000908152600560205260409020805460601c959086156105fe5761220561186c612209926124b0565b1590565b806122fb575b6122ea5761222081888588866132f3565b9061225c600061224161223860045463ffffffff1690565b97848c88612914565b60405180938192632f1c2cd560e21b83528a60048401612476565b0381305afa9586156105f9576105d09a7fed0c24299d2da4e3728deedbf20de24c4ff0e754c89f20b3d2532fe63b43b531976122d7956122a694600092611969575061192b6123a6565b5197426122bd8a600052600a602052604060002090565b556040516001600160a01b039094169693948594856131c3565b0390a36040519081529081906020820190565b634a91ec5f60e01b60005260046000fd5b50604051637347ebb960e01b81526020816004818a5afa9081156105f957600091612328575b501561220f565b61234a915060203d602011612350575b6123428183610cb1565b810190612500565b38612321565b503d612338565b5081156121cd565b3461039d57606036600319011261039d57602061237b3661069a565b63ffffffff813561238b816108b6565b16600052600182528160406000205491013560405191148152f35b60405190610d0b604083610cb1565b60405190610d0b608083610cb1565b60405190610d0b60e083610cb1565b60405190610d0b60c083610cb1565b60405190610d0b60a083610cb1565b6001600160401b038111610c7657601f01601f191660200190565b81601f8201121561039d578051612422816123f1565b926124306040519485610cb1565b8184526020828401011161039d5761244e9160208085019101610a7d565b90565b9060208282031261039d5781516001600160401b03811161039d5761244e920161240c565b60609063ffffffff61244e9493168152600160208201528160408201520190610aa0565b6040513d6000823e3d90fd5b3561244e816108b6565b90604051608081018181106001600160401b03821117610c7657604052606081935463ffffffff8116835263ffffffff8160201c16602084015263ffffffff8160401c166040840152811c910152565b9081602091031261039d575161244e8161119c565b9081602091031261039d575161244e8161038c565b6001600160a01b03166000908152600560205260409020909190612552906124b0565b6124b0565b9163ffffffff612569602085015163ffffffff1690565b16156127b2576125916060612582855163ffffffff1690565b9401516001600160a01b031690565b9260009063ffffffff1646036126dc57506040516331a9108f60e11b815260048101829052906020826024816001600160a01b0388165afa600092816126bb575b506125e35750505050600090600090565b6001600160a01b03821630036125fe57505050503090600190565b602091935b604051637f63c3dd60e01b81526001600160a01b039091166004820152602481019190915267ffffffffffffffff19909216604483015281806064810103817f0000000000000000000000000000000000007129af73c46c9f01a3fb4ff61a026001600160a01b03165afa6000918161268a575b50612683575090600090565b9160009150565b6126ad91925060203d6020116126b4575b6126a58183610cb1565b810190612515565b9038612677565b503d61269b565b6126d591935060203d6020116126b4576126a58183610cb1565b91386125d2565b906001600160a01b03841680158015612761575b15612702575050505050600090600190565b6040516331a9108f60e11b81526004810183905260209390918490839060249082905afa909181612742575b5061273c5750600093612603565b93612603565b61275a919250843d86116126b4576126a58183610cb1565b903861272e565b50604051635a2d1e0760e11b815260048101839052602081602481855afa9081156105f9578491612793575b506126f0565b6127ac915060203d602011612350576123428183610cb1565b3861278d565b505050600090600190565b929150926127fd9360018060a01b0316600052600560205263ffffffff60406127e8816000206124b0565b94828060208801511691161494015116613b16565b90612806613b7e565b91600361ffff612815856141cf565b160361284b5761244e9192604051916001600160801b03199060801b16602083015260108252612846603083610cb1565b61421b565b61ffff612857846141cf565b633a51740d60e01b6000521660045260246000fd5b81835290916001600160fb1b03831161039d5760209260051b809284830137010190565b6001600160a01b0390911681526000602082015260606040820181905261244e9391019161286c565b6001600160a01b0391821681529116602082015260606040820181905261244e9391019161286c565b634e487b7160e01b600052601160045260246000fd5b63ffffffff1660e0019063ffffffff821161290f57565b6128e2565b61296e9293915060018060a01b031660005260056020526001600160801b0363ffffffff61294560406000206124b0565b51164614806000146129bd576201adb0905b156129b457816206390e5b81871602160116613af6565b90627a12006001600160801b03831611611eee5763ffffffff166060029063ffffffff821691820361290f576129a661244e926128f8565b906129af613b7e565b613b9a565b8161c350612962565b6201b7d890612957565b908060209392818452848401376000828201840152601f01601f1916010190565b61244e94926001600160401b03604060a09463ffffffff8135612a0a816108b6565b168552602081013560208601520135612a2281610e5a565b166040830152606082015281608082015201916129c7565b60349392916bffffffffffffffffffffffff199060601b168152612a68825180936020601485019101610a7d565b019060148201520190565b6001600160401b038111610c765760051b60200190565b929192612a96826123f1565b91612aa46040519384610cb1565b82948184528183011161039d578281602093846000960137010152565b90606e1161039d57602e0190604090565b9060541161039d5760400190601490565b602083610d0b939594956040519684612b05899651809287808a019101610a7d565b8501918483013701016000815203601f198101845283610cb1565b91602061244e9381815201916129c7565b612b639163ffffffff610dcb929694959616600052600260205260406000209061ffff16600052602052604060002090565b805115612bd5578315612bcf576002841015612b9b575050612b97604051928392639a6d49cd60e01b845260048401612b20565b0390fd5b909192612bb1612bac368387612a8a565b613f74565b600081600211611b0a5750600261244e939401906001190191612ae3565b92509050565b50919061244e913691612a8a565b634e487b7160e01b600052603260045260246000fd5b9190811015612c095760051b0190565b612be3565b91602091612c279195949560408552604085019161286c565b6001600160a01b03909416910152565b919082604091031261039d5760208235612c508161038c565b92013590565b919082604091031261039d5760208235612c6f8161038c565b92013561244e8161119c565b60405190612c8a602083610cb1565b6000808352366020840137565b612caa612cc792612cb292959495612ac1565b810190612c37565b936001600160a01b0390911692810190612c56565b612de6578183612cef61254d61244e9560018060a01b03166000526005602052604060002090565b91612cf983613fac565b15612d66576001600160a01b03166000908152600760205260409020610efe9250612d3491612d2791610f49565b546001600160a01b031690565b935b604080516001600160a01b0396871660208201529590931692850192909252606084019190915282906080820190565b505060600151612d80906113a7906001600160a01b031681565b6040516331a9108f60e11b81526004810185905290602090829060249082905afa60009181612dc5575b50612dbb5750610efe600093612d36565b610efe9093612d36565b612ddf91925060203d6020116126b4576126a58183610cb1565b9038612daa565b50505061244e612c7b565b356001600160601b0319811692919060148210612e0c575050565b6001600160601b031960149290920360031b82901b16169150565b90612e3182612a73565b612e3e6040519182610cb1565b8281528092612e4f601f1991612a73565b0190602036910137565b9190811015612c095760051b81013590601e198136030182121561039d5701908135916001600160401b03831161039d57602001823603811361039d579190565b9081606091031261039d578035612eb08161038c565b9160406020830135612c508161038c565b8051821015612c095760209160051b010190565b906020808351928381520192019060005b818110612ef35750505090565b82516001600160a01b0316845260209384019390920191600101612ee6565b906020808351928381520192019060005b818110612f305750505090565b8251845260209384019390920191600101612f23565b92612f6e61244e9593612f7c9360018060a01b03168652608060208701526080860190612ed5565b908482036040860152612ed5565b916060818403910152612f12565b612fb561254d611dfd612faf612fa9612fc3966060969a99989a612ad2565b90612df1565b60601c90565b01516001600160a01b031690565b612fcc82612e27565b91612fd681612e27565b94612fe082612e27565b91600091825b8281106130cb57505050815181106130125750610efe9061244e93949560405195869460208601612f46565b929061301d84612e27565b9361302781612e27565b9161303182612e27565b9360005b83811061305b575050505061244e9394955090610efe9160405195869460208601612f46565b806130af6130a561307e838e6130a08e6130918461308b61307e60019c8e612ec1565b516001600160a01b031690565b92612ec1565b6001600160a01b039091169052565b612ec1565b6130918389612ec1565b6130b98185612ec1565b516130c48289612ec1565b5201613035565b6130d6818484612e59565b9050156131bb576131308161311d8b613091838a61310d6131036130fb848d8d612e59565b810190612e9a565b9291989093612ec1565b526001600160a01b031692612ec1565b6001600160a01b0316613091838a612ec1565b61313d61307e8289612ec1565b61314d6113a761307e848d612ec1565b6001600160a01b0390911603613168575b6001905b01612fe6565b92600180916131778688612ec1565b516131828289612ec1565b5261319d61319361307e888c612ec1565b613091838c612ec1565b6131b28b6130918361308b61307e8b85612ec1565b0193905061315e565b600190613162565b949391949290928560408201604083525260608101936000965b8088106131f957505061244e949550602081850391015261286c565b909460208060019263ffffffff8935613211816108b6565b168152019601970196906131dd565b908160011b918083046002149015171561290f57565b8181029291811591840414171561290f57565b9061325382612a73565b6132606040519182610cb1565b8281528092613271601f1991612a73565b019060005b82811061328257505050565b60209060405161329181610c7b565b60008152600083820152600060408201526000606082015260006080820152600060a0820152606060c082015282828501015201613276565b906001820180921161290f57565b906023820180921161290f57565b9190820180921161290f57565b9291926133086133038587613236565b613249565b9360006001600160401b034216967f502693d518cccccc945699ac6b0be7c02aef951c921558ec0000000000000000915b8181106133b157505050505050509061244e9161339f6133576123d3565b600281529263ffffffff7f0000000000000000000000000000000000000000000000000000000000007668166020850152600060408501526001600160401b03166060840152565b600060808301523060a083015261412d565b60005b8481106133c45750600101613339565b61340a6133e66133dd6133d884898c612bf9565b6124a6565b63ffffffff1690565b63ffffffff908060031c600052600c60205260e06040600020549160051b161c1690565b63ffffffff811615610ffe578484613421856132ca565b61342b8286613236565b613434916132e6565b61ffff1692888c878d88613449818684612bf9565b613452906124a6565b9461345c92612bf9565b613465906124a6565b61346e906136d8565b6001600160a01b03169461348192612bf9565b604051631a98288d60e11b60208201526001600160a01b038d1660248201529035604482015267ffffffffffffffff199490941660648086019190915284526134cb608485610cb1565b6134d36123c4565b61ffff909516855263ffffffff166020850152600060408501526001600160401b038e16606085015261ffff1660808401526001600160a01b031660a083015260c0820152816135238785613236565b9061352d916132e6565b90613538828c612ec1565b52613543908a612ec1565b506001016133b4565b6040519061355982610c96565b60006020838281520152565b919082604091031261039d5760405161357d81610c96565b6020808294805184520151910152565b9060408282031261039d5761244e91613565565b906020909392936040835263ffffffff815116604084015281810151606084015260806135f56135df604084015160a08488015260e0870190610aa0565b6060840151868203603f190160a0880152610aa0565b910151151560c08401526001600160a01b03909416910152565b61366f9260409261361e61354c565b50613628836136d8565b61363f6136336123e2565b63ffffffff9095168552565b602084015283830152606082015260006080820152815180938192631bb8518b60e31b83523090600484016135a1565b03817f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b03165afa9081156105f9576000916136af575090565b61244e915060403d6040116136d1575b6136c98183610cb1565b81019061358d565b503d6136bf565b63ffffffff168060005260016020526040600020549081156136f8575090565b63f6ff4fb760e01b60005260045260246000fd5b61c34f1981019190821161290f57565b9190820391821161290f57565b3561244e81610e5a565b6040906001600160401b0361244e94931681528160208201520190610aa0565b93929192613763600b5460ff1690565b9081613893575b5061388257610efe613793926040519485936304c98a8b60e51b602086015287602486016129e8565b6137a6816137a05a61370c565b30613ca4565b9190156137b257505050565b63ffffffff7fd191660d5fb7fa40de3038f810fa899670f44a26d29f0609702b778de1c4e5f6916040516137f181610efe602082019446903087612a3a565b51902061387d61386e61386861381f613809896124a6565b63ffffffff166000526008602052604060002090565b976138396020820135809a90600052602052604060002090565b94613862604083019661384b88613729565b6001600160401b0316600052602052604060002090565b556124a6565b92613729565b94604051938493169583613733565b0390a3565b6341c8302160e11b60005260046000fd5b6001600160a01b031660009081526009602052604090205460ff161590503861376a565b3360009081527f460e1c17541eb4600da639136d22ecdece50dfd5504d40fe2d419370e887d378602052604090205460ff16156138f057565b63e2517d3f60e01b600052336004527f8970ff45bc1804c7a79662cce9df9b0403588be8e486c6f5a410a2814caa892c60245260446000fd5b600081815260036020908152604080832033845290915290205460ff161561394e5750565b63e2517d3f60e01b6000523360045260245260446000fd5b60008181526003602090815260408083206001600160a01b038616845290915290205460ff166139f35760008181526003602090815260408083206001600160a01b03861684529091529020805460ff1916600117905533916001600160a01b0316907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d600080a4600190565b5050600090565b6000546001600160a01b03163303613a0e57565b63118cdaa760e01b6000523360045260246000fd5b7f238399d427b947898edb290f5ff0f9109849b1c3ba196a42e35f00c50a54b98b9163ffffffff604092169081600052600160205280836000205582519182526020820152a1565b60008181526003602090815260408083206001600160a01b038616845290915290205460ff16156139f35760008181526003602090815260408083206001600160a01b03861684529091529020805460ff1916905533916001600160a01b0316907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b600080a4600190565b906001600160801b03809116911601906001600160801b03821161290f57565b916001600160801b03613b4e948193948180613b73575b15613b6957905b15613b645762031c870181165b16026201adb00116613af6565b90627a12006001600160801b03831611611eee57565b613b41565b5061c35090613b34565b508281161515613b2d565b604051600360f01b60208201526002815261244e602282610cb1565b9091600361ffff613baa846141cf565b1603613c985760405160809390931b6fffffffffffffffffffffffffffffffff1916602084015260e01b6001600160e01b031916603083015260148252613bf2603483610cb1565b600361ffff613c00836141cf565b1603613c8c57600161ffff613c1584516148cd565b16019161ffff831161290f5761244e9160206004926040519583613c428895518092868089019101610a7d565b840190600160f81b8483015261ffff60f01b9060f01b166021820152600560f81b6023820152613c7b8251809385602485019101610a7d565b01010301601f198101835282610cb1565b61285761ffff916141cf565b61ffff612857836141cf565b929190600091829182613cb760046123f1565b96613cc56040519889610cb1565b60048852601f19613cd660046123f1565b013660208a013760208451940192f13d60048111613cfd575b8084526000602085013e9190565b506004613cef565b601f8211613d1257505050565b6000526020600020906020601f840160051c83019310613d4d575b601f0160051c01905b818110613d41575050565b60008155600101613d36565b9091508190613d2d565b91909182516001600160401b038111610c7657613d7e81613d788454610c0b565b84613d05565b6020601f8211600114613dbf578190613db0939495600092613db4575b50508160011b916000199060031b1c19161790565b9055565b015190503880613d9b565b601f19821690613dd484600052602060002090565b9160005b818110613e1057509583600195969710613df7575b505050811b019055565b015160001960f88460031b161c19169055388080613ded565b9192602060018192868b015181550194019201613dd8565b602081016020825282518091526040820191602060408360051b8301019401926000915b838310613e5b57505050505090565b9091929394602080613e9e600193603f19868203018752606060408b5163ffffffff815116845261ffff8682015116868501520151918160408201520190610aa0565b97019301930191939290613e4c565b60005b8151811015613f3d5780613ed36040613ecb60019486612ec1565b510151613f74565b613f376040613ee28386612ec1565b51015163ffffffff613ef48487612ec1565b5151166000526002602052613f326040600020613f206020613f16878a612ec1565b51015161ffff1690565b61ffff16600052602052604060002090565b613d57565b01613eb0565b50613f6f7fbe4864a8e820971c0247f5992e2da559595f7bf076a21cb5928d443d2a13b6749160405191829182613e28565b0390a1565b600361ffff60028301511603613f875750565b604051639a6d49cd60e01b815260206004820152908190612b97906024830190610aa0565b63ffffffff815116156105fe5763ffffffff905116461490565b60405190613fd382610c5b565b8160008152600060208201526040613fe961354c565b910152565b9060808282031261039d5761402890604080519361400b85610c5b565b80518552602081015161401d81610e5a565b602086015201613565565b604082015290565b614099608094926140b59694614044613fc6565b50602061405186516146a8565b95019182518061411e575b50614066856136d8565b92511515926140826140766123e2565b63ffffffff9097168752565b602086015260408501526060840152151585830152565b6040518095819482936302637a4560e41b8452600484016135a1565b03917f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b03165af19081156105f9576000916140f5575090565b61244e915060803d608011614117575b61410f8183610cb1565b810190613fee565b503d614105565b614127906146c7565b3861405c565b91909161413a81516148cd565b604051600160f01b60208201526000602282015260f09190911b6001600160f01b031916602482015260068152614172602682610cb1565b916000925b825184101561419f576141976001916141908686612ec1565b5190614e82565b930192614177565b92509290508163ffffffff6141bb602084015163ffffffff1690565b166141c557505090565b61244e92506147d6565b60028151106141df576002015190565b60405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b6044820152606490fd5b600361ffff614229836141cf565b1603613c8c57600161ffff61423e84516148cd565b16019161ffff831161290f5761244e916020600492604051958361426b8895518092868089019101610a7d565b600160f81b90850184810182905260f09290921b6001600160f01b03191660218301526023820152815191613c7b90839060248401908601610a7d565b9080601f8301121561039d5781356142bf81612a73565b926142cd6040519485610cb1565b81845260208085019260051b82010192831161039d57602001905b8282106142f55750505090565b81358152602091820191016142e8565b9160608383031261039d57823561431b8161038c565b92602081013561432a8161038c565b9260408201356001600160401b03811161039d5761244e92016142a8565b90612c27602091949394604084526040840190612f12565b3d1561438b573d90614371826123f1565b9161437f6040519384610cb1565b82523d6000602084013e565b606090565b9080601f8301121561039d5781356143a781612a73565b926143b56040519485610cb1565b81845260208085019260051b82010192831161039d57602001905b8282106143dd5750505090565b6020809183356143ec8161038c565b8152019101906143d0565b9060808282031261039d57813561440d8161038c565b9260208301356001600160401b03811161039d578261442d918501614390565b9260408101356001600160401b03811161039d578361444d918301614390565b9260608201356001600160401b03811161039d5761244e92016142a8565b61447a919392938101906143f7565b6001600160a01b03909316600081815260066020526040902091929161449f90612d27565b916144c261186c61254d8560018060a01b03166000526005602052604060002090565b156144d4575050610d0b939450614ad5565b91509360005b845181101561465b576000806144f361307e8487612ec1565b61450061307e8589612ec1565b9061450b858a612ec1565b51906001600160a01b03811615841461458457506040516340c10f1960e01b602082019081526001600160a01b03909316602482015260448101919091526145568160648101610efe565b5190828a5af1614564614360565b5015614574576001905b016144da565b62ec6f7b60e31b60005260046000fd5b916001600160a01b0381161584146145ee5750604051630852cd8d60e31b6020820190815260248201929092529091506145c18160448101610efe565b5190828a5af16145cf614360565b50156145dd5760019061456e565b631bc5aabf60e21b60005260046000fd5b6040516323b872dd60e01b602082019081526001600160a01b039485166024830152939091166044820152606481019190915261462e8160848101610efe565b5190828a5af161463c614360565b501561464a5760019061456e565b6312171d8360e31b60005260046000fd5b50949392505050803b1561039d5760405163163b5cc360e31b815260048101929092526000908290602490829084905af180156105f9576146995750565b806119f66000610d0b93610cb1565b8034036146b25790565b6304fb820960e51b6000523460045260246000fd5b60405163393f876560e21b81527f0000000000000000000000006f475642a6e85809b1c36fa62763669b1b48dd5b6001600160a01b031690602081600481855afa9081156105f9576000916147b7575b506001600160a01b03169182156147a6576040516323b872dd60e01b60208281019182523360248401526001600160a01b03909416604483015260648201929092526000919061476a8160848101610efe565b519082855af11561249a576000513d61479d5750803b155b6147895750565b635274afe760e01b60005260045260246000fd5b60011415614782565b6329b99a9560e11b60005260046000fd5b6147d0915060203d6020116126b4576126a58183610cb1565b38614717565b61244e9060276020936148be60ff825116916148aa63ffffffff888301511691604081015115156001600160401b036060830151169061ffff6080840151169260a0600180821b0391015116946040519b8c9a61483c828d019182815194859201610a7d565b600160f81b9101908152600160f01b600182015260f898891b6001600160f81b031916600382015260e09190911b6001600160e01b031916600482015290151590961b600887015260c01b6001600160c01b031916600986015260f01b6001600160f01b0319166011850152565b60601b6001600160601b0319166013830152565b0103601f198101835282610cb1565b61ffff81116148dd5761ffff1690565b6306dfcc6560e41b600052601060045260245260446000fd5b60005b8351811015614985576001600160a01b0382166149168286612ec1565b5190803b1561039d576040516323b872dd60e01b81523060048201526001600160a01b038616602482015260448101929092526000908290606490829084905af180156105f95761496b575b506001016148f9565b8061497860008093610cb1565b80031261039d5738614962565b50610d0b929150614f30565b9061499b82612a73565b6149a86040519182610cb1565b82815280926149b9601f1991612a73565b019060005b8281106149ca57505050565b8060606020809385010152016149be565b60208183031261039d578051906001600160401b03821161039d57019080601f8301121561039d578151614a0e81612a73565b92614a1c6040519485610cb1565b81845260208085019260051b8201019183831161039d5760208201905b838210614a4857505050505090565b81516001600160401b03811161039d57602091614a6a8784809488010161240c565b815201910190614a39565b602081016020825282518091526040820191602060408360051b8301019401926000915b838310614aa857505050505090565b9091929394602080614ac6600193603f198682030187528951610aa0565b97019301930191939290614a99565b909291614aea614ae58251613220565b614991565b600094855b8351811015614ce157614b0561307e8284612ec1565b614b0f8286612ec1565b5190614b34612d2783610f498a60018060a01b03166000526007602052604060002090565b6040516331a9108f60e11b8152600481018490526020816024816001600160a01b038d165afa9081156105f957600091614cc3575b50306001600160a01b0390911603614cb2576001600160a01b038116614c41575b506001600160a01b038116614ba4575b5050600101614aef565b60405163b18e2bbb60e01b60208201526001600160a01b038083166024830152881660448201526064810183905264ffffffffff6084820152600160a482018190529299929392614c3a9291611d9d918691614c038160c48101610efe565b614c0d828b612ec1565b52614c18818a612ec1565b506001600160a01b038b16600090815260076020526040902091019b90610f49565b9038614b9a565b60405163b18e2bbb60e01b60208201526001600160a01b03918216602482015290881660448201526064810183905264ffffffffff6084820152600060a48201529098600191614c948160c48101610efe565b614c9e8288612ec1565b52614ca98187612ec1565b50019738614b8a565b6349e27cff60e01b60005260046000fd5b614cdb915060203d81116126b4576126a58183610cb1565b38614b69565b50509293915050614cf181614991565b9160005b828110614d80575050614d055750565b6000614d259160405180938192631592ca1b60e31b835260048301614a75565b0381837f00000000000000000000000000000000000000447e69651d841bd8d104bed4936001600160a01b03165af180156105f957614d615750565b614d7d903d806000833e614d758183610cb1565b8101906149db565b50565b80614d8d60019284612ec1565b51614d988287612ec1565b52614da38186612ec1565b5001614cf5565b602090614dc2600b9694959382815194859201610a7d565b600160f81b910190815260f093841b6001600160f01b03199081166001830152600160f01b60038301529190931b16600583015260e01b6001600160e01b03191660078201520190565b602090614e27601f9897959396949682815194859201610a7d565b94151560f81b940193845260c01b6001600160c01b031916600184015260f01b6001600160f01b031916600983015260601b6001600160601b031916600b820152815191614e7d90839085840190602001610a7d565b010190565b9061244e90610efe614e96825161ffff1690565b91614ede60c0820195614ed0614eb5614eb08951516132d8565b6148cd565b602085015163ffffffff169060405197889460208601614daa565b03601f198101855284610cb1565b6040810151151594614efa60608301516001600160401b031690565b91614f1e60a0614f0f608084015161ffff1690565b9201516001600160a01b031690565b91519260405197889660208801614e0c565b919091614f3d8351614991565b600091825b855181101561503d57614f558187612ec1565b5193614f7a612d2786610f498660018060a01b03166000526007602052604060002090565b6001600160a01b038116156150325760405163b18e2bbb60e01b60208201526001600160a01b03918216602482015290841660448201526064810186905264ffffffffff6084820152600060a48201526001929161502c9161501c918591614fe58160c48101610efe565b614fef868a612ec1565b52614ffa8589612ec1565b506001600160a01b038716600090815260076020526040902091019790610f49565b80546001600160a01b0319169055565b01614f42565b50935060019061502c565b505091925061504b81614991565b9160005b82811061505f575050614d055750565b8061506c60019284612ec1565b516150778287612ec1565b526150828186612ec1565b500161504f56fea2646970667358221220e40b6d1cbc769734a9e93e86e73c5e53f52e0ab913b57d4d7ec28c3efef89db364736f6c634300081d0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000506aa8bc5da44f9b3329b8c6f7e00000000000000000000000005454757e592aedf88b9786313e878ed65b96367700000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000447e69651d841bd8d104bed4930000000000000000000000000000000000007129af73c46c9f01a3fb4ff61a020000000000000000000000005454757e592aedf88b9786313e878ed65b963677
-----Decoded View---------------
Arg [0] : _endpointLocator (address): 0x000000000000506Aa8Bc5DA44F9b3329b8c6f7E0
Arg [1] : _delegate (address): 0x5454757e592aEdf88B9786313E878ED65B963677
Arg [2] : _readChannel (uint32): 4294967295
Arg [3] : _delegatexyz (address): 0x00000000000000447e69651d841bD8D104Bed493
Arg [4] : _exclusiveDelegateResolver (address): 0x0000000000007129AF73C46C9F01a3fB4FF61A02
Arg [5] : _initialAdmin (address): 0x5454757e592aEdf88B9786313E878ED65B963677
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 000000000000000000000000000000000000506aa8bc5da44f9b3329b8c6f7e0
Arg [1] : 0000000000000000000000005454757e592aedf88b9786313e878ed65b963677
Arg [2] : 00000000000000000000000000000000000000000000000000000000ffffffff
Arg [3] : 00000000000000000000000000000000000000447e69651d841bd8d104bed493
Arg [4] : 0000000000000000000000000000000000007129af73c46c9f01a3fb4ff61a02
Arg [5] : 0000000000000000000000005454757e592aedf88b9786313e878ed65b963677
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.