Source Code
Overview
MON Balance
MON Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 2 internal transactions
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 33766532 | 79 days ago | Contract Creation | 0 MON | |||
| 33766532 | 79 days ago | Contract Creation | 0 MON |
Loading...
Loading
Contract Name:
RulesetWhitelist
Compiler Version
v0.8.24+commit.e11b9ed9
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import "./RulesetBase.sol";
import "../interfaces/IWhitelistExtension.sol";
import "@limitbreak/tm-core-lib/src/utils/token/IEOARegistry.sol";
/**
* @title RulesetWhitelist
* @author Limit Break, Inc.
* @notice A ruleset contract that blocks transfers by default, unless exceptions are made through various options and
* whitelisting rules.
*/
contract RulesetWhitelist is IRuleset, RulesetBase {
using EnumerableSet for EnumerableSet.AddressSet;
using EnumerableSet for EnumerableSet.Bytes32Set;
struct Options {
bool enableAccountFreezingMode;
bool disableAuthorizationMode;
bool customListSupplementsDefaultList;
bool blockSmartWalletReceivers;
bool blockUnverifiedEOAReceivers;
bool blockAllOTC;
bool allowOTCFor7702Delegates;
bool allowOTCForSmartWallets;
}
/// @dev The address of the EOA Registry to use to validate an account is a verified EOA.
address private immutable _eoaRegistry;
constructor(address eoaRegistry_) RulesetBase() {
if (eoaRegistry_ == address(0)) {
revert CreatorTokenTransferValidator__InvalidConstructorArgs();
}
_eoaRegistry = eoaRegistry_;
}
/**
* @notice Validates a transfer of a Creator Token.
*
* @notice Global Options Used:
* - Disable Authorization Mode: Toggles authorization mode logic on/off (default: enabled)
* - Enable Account Freezing Mode: Toggles account freezing logic on/off (default: disabled)
* - Custom List Supplements Default List Mode: When toggled on, whitelist includes both custom list
* values and default managed list values (default: off)
*
* @notice Ruleset-Specific Options Used:
* - Block Smart Wallet Receivers: When enabled, blocks transfers to receivers with
* code length > 0, unless `to` is whitelisted (default: disabled)
* - Block Unverified EOA Receivers: When enabled, blocks transfers to receivers that have not verified
* an ECDSA signature on the EOA registry, unless `to` is whitelisted
* (default: disabled)
* - Block All OTC: When enabled, blocks all OTC transfers, unless `caller` or `from` are whitelisted
* (default: disabled)
* [OTC transfer is defined as any owner-initiated transfer where caller == from]
* - Allow OTC For 7702 Delegates: Unused when Block All OTC is enabled. When enabled, allows OTC transfers
* from EOAs that currently have EIP-7702 delegates attached. When disabled,
* blocks OTC transfers from EOAs that currently have EIP-7702 delegates
* attached, unless the attached delegate is whitelisted.
* (default: disabled)
* - Allow OTC For Smart Wallets: Unused when Block All OTC is enabled. When enabled, allows OTC transfers
* from smart wallets. When disabled, blocks OTC transfers from smart wallets,
* unless the smart wallet is whitelisted. (default: disabled)
*
* @notice Validation Flow:
* 1. If account freezing mode is enabled, check if the sender or recipient is frozen.
* If frozen, block transfer and return.
* 2. If authorization mode is enabled, check if an authorizer has pre-authorized transfer of
* collection/token id/amount by operator (msg.sender). If authorized, allow transfer and return.
* 3. If block smart wallet receivers is enabled, check if the receiver has code length > 0. If so,
* check if the receiver is whitelisted. If not whitelisted, block transfer and return.
* If whitelisted, continue.
* 4. If block unverified EOA receivers is enabled, check if the receiver has verified an ECDSA signature
* on the EOA registry. If not verified, check if the receiver is whitelisted. If not whitelisted,
* block transfer and return. If whitelisted, continue.
* 5. If transfer is OTC (caller == from):
* 5a. If block all OTC is enabled, check if `caller` or `from` are whitelisted.
* If not whitelisted, block transfer and return. If whitelisted, allow transfer and return.
* 5b. If block all OTC is disabled, and code length of `from` address equals 0, allow transfer and return.
* 5c. If block all OTC is disabled, and code length of `from` address is greater than 0:
* 5ci. If `from` is an EOA with delegation attached: when allow OTC for 7702 delegates is enabled,
* allow transfer an return. Otherwise, when allow OTC for 7702 delegates is disabled, check
* if delegate is whitelisted. If not whitelisted, block transfer and return. If whitelisted,
* allow transfer and return.
* 5cii. Otherwise, `from` is a smart wallet. If allow OTC for smart wallets is enabled, allow
* transfer and return. Otherwise, check if `from` is whitelisted. If not whitelisted, block
* transfer and return. If whitelisted, allow transfer and return.
* 6. If transfer is not OTC (caller != from), check if `caller` is whitelisted. If not whitelisted,
* block transfer and return. If whitelisted, allow transfer and return.
*
* @notice Whitelisting Notes:
* - When performing a whitelist check, when custom list supplements default list mode is enabled, the
* default whitelist is checked first. If the operator is not whitelisted in the default list, the
* custom list specified in the collection security policy is checked.
* - When performing whitelist checks, accounts are first checked by address, then by codehash, and finally
* evaluated against a set of 0 or more whitelist extensions.
*/
function validateTransfer(
uint256 authorizerCheckType,
address collection,
address caller,
address from,
address to,
uint256 tokenId,
uint256 amount) external view returns (bytes4) {
CollectionSecurityPolicy storage collectionSecurityPolicy =
validatorStorage().collectionSecurityPolicies[collection];
Options memory opts =
_getOptions(collectionSecurityPolicy.globalOptions, collectionSecurityPolicy.rulesetOptions);
if (opts.enableAccountFreezingMode) {
AccountList storage frozenAccountList = validatorStorage().frozenAccounts[collection];
if (frozenAccountList.nonEnumerableAccounts[from]) {
return CreatorTokenTransferValidator__SenderAccountIsFrozen.selector;
}
if (frozenAccountList.nonEnumerableAccounts[to]) {
return CreatorTokenTransferValidator__ReceiverAccountIsFrozen.selector;
}
}
if (!opts.disableAuthorizationMode) {
if (_isAuthorized(authorizerCheckType, collection, caller, tokenId, amount)) {
return SELECTOR_NO_ERROR;
}
}
return _doWhitelistChecks(
opts,
collectionSecurityPolicy.listId,
collection,
to,
caller,
from);
}
function _doWhitelistChecks(
Options memory opts,
uint48 listId,
address collection,
address to,
address caller,
address from
) internal view returns (bytes4) {
(
mapping (address => bool) storage accountWhitelist,
mapping (bytes32 => bool) storage codehashWhitelist,
EnumerableSet.AddressSet storage whitelistExtensions
) = _getWhitelistStoragePointers(listId);
if (opts.blockSmartWalletReceivers) {
if (_getCodeLengthAsm(to) > 0) {
if (!_isWhitelisted(opts.customListSupplementsDefaultList, accountWhitelist, codehashWhitelist, whitelistExtensions, collection, to)) {
return CreatorTokenTransferValidator__ReceiverMustNotHaveDeployedCode.selector;
}
}
}
if (opts.blockUnverifiedEOAReceivers) {
if (!_isVerifiedEOA(to)) {
if (!_isWhitelisted(opts.customListSupplementsDefaultList, accountWhitelist, codehashWhitelist, whitelistExtensions, collection, to)) {
return CreatorTokenTransferValidator__ReceiverProofOfEOASignatureUnverified.selector;
}
}
}
if (caller == from) {
if (!opts.blockAllOTC) {
if (_getCodeLengthAsm(from) > 0) {
(bool isDelegate, address delegate) = _check7702(from);
if (opts.allowOTCFor7702Delegates) {
// If allowing OTC for 7702 delegates, check if the owner is delegated or not
if (!isDelegate) {
// This is a non-delegated smart wallet account, if OTC is not allowed for smart wallets check against whitelist
if (!opts.allowOTCForSmartWallets) {
if (!_isWhitelisted(opts.customListSupplementsDefaultList, accountWhitelist, codehashWhitelist, whitelistExtensions, collection, from)) {
return CreatorTokenTransferValidator__OTCNotAllowedForSmartWallets.selector;
}
}
}
} else {
// If not allowing OTC for 7702 delegates, check if the owner is delegated or not
if (isDelegate) {
// This is a delegated EOA account, block unless delegate is whitelisted
if (!_is7702DelegateWhitelisted(opts.customListSupplementsDefaultList, listId, collection, delegate)) {
return CreatorTokenTransferValidator__OTCNotAllowedFor7702Delegates.selector;
}
} else {
// This is a non-delegated smart wallet account, if OTC is not allowed for smart wallets check against whitelist
if (!opts.allowOTCForSmartWallets) {
if (!_isWhitelisted(opts.customListSupplementsDefaultList, accountWhitelist, codehashWhitelist, whitelistExtensions, collection, from)) {
return CreatorTokenTransferValidator__OTCNotAllowedForSmartWallets.selector;
}
}
}
}
}
return SELECTOR_NO_ERROR;
}
}
if (!_isWhitelisted(opts.customListSupplementsDefaultList, accountWhitelist, codehashWhitelist, whitelistExtensions, collection, caller, from)) {
return CreatorTokenTransferValidator__CallerOrFromMustBeWhitelisted.selector;
}
return SELECTOR_NO_ERROR;
}
function _isWhitelisted(
bool customListSupplementsDefaultList,
mapping (address => bool) storage accountWhitelist,
mapping (bytes32 => bool) storage codehashWhitelist,
EnumerableSet.AddressSet storage whitelistExtensions,
address collection,
address account
) internal view returns (bool isWhitelisted) {
if (customListSupplementsDefaultList) {
(
mapping (address => bool) storage defaultAccountWhitelist,
mapping (bytes32 => bool) storage defaultCodehashWhitelist,
EnumerableSet.AddressSet storage defaultWhitelistExtensions
) = _getWhitelistStoragePointers(DEFAULT_LIST_ID);
if (_checkWhitelist(
defaultAccountWhitelist,
defaultCodehashWhitelist,
defaultWhitelistExtensions,
collection,
account)) {
return true;
}
}
return _checkWhitelist(accountWhitelist, codehashWhitelist, whitelistExtensions, collection, account);
}
function _isWhitelisted(
bool customListSupplementsDefaultList,
mapping (address => bool) storage accountWhitelist,
mapping (bytes32 => bool) storage codehashWhitelist,
EnumerableSet.AddressSet storage whitelistExtensions,
address collection,
address account1,
address account2
) internal view returns (bool isWhitelisted) {
if (customListSupplementsDefaultList) {
(
mapping (address => bool) storage defaultAccountWhitelist,
mapping (bytes32 => bool) storage defaultCodehashWhitelist,
EnumerableSet.AddressSet storage defaultWhitelistExtensions
) = _getWhitelistStoragePointers(DEFAULT_LIST_ID);
if (_checkWhitelist(
defaultAccountWhitelist,
defaultCodehashWhitelist,
defaultWhitelistExtensions,
collection,
account1,
account2)) {
return true;
}
}
return _checkWhitelist(accountWhitelist, codehashWhitelist, whitelistExtensions, collection, account1, account2);
}
function _is7702DelegateWhitelisted(
bool customListSupplementsDefaultList,
uint48 listId,
address collection,
address account
) internal view returns (bool isWhitelisted) {
if (customListSupplementsDefaultList) {
(
mapping (address => bool) storage defaultAccountWhitelist,
mapping (bytes32 => bool) storage defaultCodehashWhitelist,
EnumerableSet.AddressSet storage defaultWhitelistExtensions
) = _get7702DelegateWhitelistStoragePointers(DEFAULT_LIST_ID);
if (_checkWhitelist(
defaultAccountWhitelist,
defaultCodehashWhitelist,
defaultWhitelistExtensions,
collection,
account)) {
return true;
}
}
(
mapping (address => bool) storage accountWhitelist,
mapping (bytes32 => bool) storage codehashWhitelist,
EnumerableSet.AddressSet storage whitelistExtensions
) = _get7702DelegateWhitelistStoragePointers(listId);
return _checkWhitelist(accountWhitelist, codehashWhitelist, whitelistExtensions, collection, account);
}
function _checkWhitelist(
mapping (address => bool) storage accountWhitelist,
mapping (bytes32 => bool) storage codehashWhitelist,
EnumerableSet.AddressSet storage whitelistExtensions,
address collection,
address account
) internal view returns (bool isWhitelisted) {
isWhitelisted =
accountWhitelist[account] ||
codehashWhitelist[_getCodeHashAsm(account)];
if (!isWhitelisted) {
uint256 lengthOfExtensionsList = whitelistExtensions.length();
for (uint256 i = 0; i < lengthOfExtensionsList; ++i) {
IWhitelistExtension whitelistExtension = IWhitelistExtension(whitelistExtensions.at(i));
if (whitelistExtension.isWhitelisted(collection, account)) {
isWhitelisted = true;
break;
}
}
}
}
function _checkWhitelist(
mapping (address => bool) storage accountWhitelist,
mapping (bytes32 => bool) storage codehashWhitelist,
EnumerableSet.AddressSet storage whitelistExtensions,
address collection,
address account1,
address account2
) internal view returns (bool isWhitelisted) {
isWhitelisted =
accountWhitelist[account1] ||
accountWhitelist[account2] ||
codehashWhitelist[_getCodeHashAsm(account1)] ||
codehashWhitelist[_getCodeHashAsm(account2)];
if (!isWhitelisted) {
uint256 lengthOfExtensionsList = whitelistExtensions.length();
for (uint256 i = 0; i < lengthOfExtensionsList; ++i) {
IWhitelistExtension whitelistExtension = IWhitelistExtension(whitelistExtensions.at(i));
if (whitelistExtension.isWhitelisted(collection, account1) ||
whitelistExtension.isWhitelisted(collection, account2)) {
isWhitelisted = true;
break;
}
}
}
}
/// @notice Returns true if the specified account has verified a signature on the registry, false otherwise.
function _isVerifiedEOA(address account) internal view returns (bool) {
return IEOARegistry(_eoaRegistry).isVerifiedEOA(account);
}
function _getOptions(uint8 globalOptions, uint16 whitelistOptions) internal pure returns (Options memory options) {
options.enableAccountFreezingMode =
_isFlagSet(globalOptions, FLAG_GLOBAL_ENABLE_ACCOUNT_FREEZING_MODE);
options.disableAuthorizationMode =
_isFlagSet(globalOptions, FLAG_GLOBAL_DISABLE_AUTHORIZATION_MODE);
options.customListSupplementsDefaultList =
_isFlagSet(globalOptions, FLAG_GLOBAL_CUSTOM_LIST_SUPPLEMENTS_DEFAULT_LIST);
options.blockSmartWalletReceivers =
_isFlagSet(whitelistOptions, FLAG_RULESET_WHITELIST_BLOCK_SMART_WALLET_RECEIVERS);
options.blockUnverifiedEOAReceivers =
_isFlagSet(whitelistOptions, FLAG_RULESET_WHITELIST_BLOCK_UNVERIFIED_EOA_RECEIVERS);
options.blockAllOTC =
_isFlagSet(whitelistOptions, FLAG_RULESET_WHITELIST_BLOCK_ALL_OTC);
options.allowOTCFor7702Delegates =
_isFlagSet(whitelistOptions, FLAG_RULESET_WHITELIST_ALLOW_OTC_FOR_7702_DELEGATES);
options.allowOTCForSmartWallets =
_isFlagSet(whitelistOptions, FLAG_RULESET_WHITELIST_ALLOW_OTC_FOR_SMART_WALLETS);
}
function _getWhitelistStoragePointers(uint48 listId)
internal
view
returns (
mapping (address => bool) storage accountWhitelist,
mapping (bytes32 => bool) storage codehashWhitelist,
EnumerableSet.AddressSet storage whitelistExtensions
) {
List storage whitelist = validatorStorage().lists[LIST_TYPE_WHITELIST][listId];
accountWhitelist = whitelist.nonEnumerableAccounts;
codehashWhitelist = whitelist.nonEnumerableCodehashes;
whitelistExtensions =
validatorStorage().lists[EXPANSION_LIST_TYPE_WHITELIST_EXTENSION_CONTRACTS][listId].enumerableAccounts;
}
function _get7702DelegateWhitelistStoragePointers(uint48 listId)
internal
view
returns (
mapping (address => bool) storage accountWhitelist,
mapping (bytes32 => bool) storage codehashWhitelist,
EnumerableSet.AddressSet storage whitelistExtensions
) {
List storage whitelist =
validatorStorage().lists[EXPANSION_LIST_TYPE_7702_DELEGATE_WHITELIST][listId];
accountWhitelist = whitelist.nonEnumerableAccounts;
codehashWhitelist = whitelist.nonEnumerableCodehashes;
whitelistExtensions =
validatorStorage().lists[EXPANSION_LIST_TYPE_7702_DELEGATE_WHITELIST_EXTENSION_CONTRACTS][listId].enumerableAccounts;
}
}pragma solidity ^0.8.4;
/**
* @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);
}pragma solidity ^0.8.24;
library StorageTstorish {
// keccak256(abi.encode(uint256(keccak256("storage.Tstorish")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant DATA_STORAGE_SLOT =
0xdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b00;
struct Data {
// Indicates if TSTORE support has been activated during or post-deployment.
bool tstoreSupport;
}
function data() internal pure returns (Data storage ptr) {
bytes32 slot = DATA_STORAGE_SLOT;
assembly {
ptr.slot := slot
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "./StorageTstorish.sol";
/**
* @title Tloadish
* @notice Based on https://github.com/ProjectOpenSea/tstorish/commit/a81ed74453ed7b9fe7e96a9906bc4def19b73e33
*/
abstract contract Tloadish {
/*
* ------------------------------------------------------------------------+
* Opcode | Mnemonic | Stack | Memory |
* ------------------------------------------------------------------------|
* 60 0x02 | PUSH1 0x02 | 0x02 | |
* 60 0x1e | PUSH1 0x1e | 0x1e 0x02 | |
* 61 0x3d5c | PUSH2 0x3d5c | 0x3d5c 0x1e 0x02 | |
* 3d | RETURNDATASIZE | 0 0x3d5c 0x1e 0x02 | |
* |
* :: store deployed bytecode in memory: (3d) RETURNDATASIZE (5c) TLOAD :: |
* 52 | MSTORE | 0x1e 0x02 | [0..0x20): 0x3d5c |
* f3 | RETURN | | [0..0x20): 0x3d5c |
* ------------------------------------------------------------------------+
*/
uint256 constant _TLOAD_TEST_PAYLOAD = 0x6002_601e_613d5c_3d_52_f3;
uint256 constant _TLOAD_TEST_PAYLOAD_LENGTH = 0x0a;
uint256 constant _TLOAD_TEST_PAYLOAD_OFFSET = 0x16;
// Declare an immutable variable to store the tload test contract address.
address private immutable _tloadTestContract;
// Declare an immutable variable to store the initial TLOAD support status.
bool internal immutable _tloadInitialSupport;
// Declare an immutable function type variable for the _getTloadish function
// based on chain support for tload at time of deployment.
function(uint256) view returns (uint256) internal immutable _getTstorish;
// Declare a few custom revert error types.
error TloadTestContractDeploymentFailed();
/**
* @dev Determine TLOAD availability during deployment. This involves
* attempting to deploy a contract that utilizes TLOAD as part of the
* contract construction bytecode, and configuring initial support for
* using TLOAD in place of SLOAD based on the result.
*/
constructor() {
// Deploy the contract testing TLOAD support and store the address.
address tloadTestContract = _prepareTloadTest();
// Ensure the deployment was successful.
if (tloadTestContract == address(0)) {
revert TloadTestContractDeploymentFailed();
}
// Determine if TLOAD is supported.
_tloadInitialSupport = StorageTstorish.data().tstoreSupport = _testTload(tloadTestContract);
if (_tloadInitialSupport) {
// If TLOAD is supported, set functions to their versions that use
// tload directly without support checks.
_getTstorish = _getTstore;
} else {
// If TLOAD is not supported, set functions to their versions that
// fallback to sload until tstoreSupport is true.
_getTstorish = _getTstorishWithSloadFallback;
}
// Set the address of the deployed TLOAD test contract as an immutable.
_tloadTestContract = tloadTestContract;
}
/**
* @dev Private function to read a TSTORISH value. Assigned to _getTstorish
* internal function variable at construction if chain has tload support.
*
* @param storageSlot The slot to read the TSTORISH value from.
*
* @return value The TSTORISH value at the given storage slot.
*/
function _getTstore(
uint256 storageSlot
) internal view returns (uint256 value) {
assembly {
value := tload(storageSlot)
}
}
/**
* @dev Private function to read a TSTORISH value with sload fallback.
* Assigned to _getTstorish internal function variable at construction
* if chain does not have tload support.
*
* @param storageSlot The slot to read the TSTORISH value from.
*
* @return value The TSTORISH value at the given storage slot.
*/
function _getTstorishWithSloadFallback(
uint256 storageSlot
) internal view returns (uint256 value) {
if (StorageTstorish.data().tstoreSupport) {
assembly {
value := tload(storageSlot)
}
} else {
assembly {
value := sload(storageSlot)
}
}
}
/**
* @dev Private function to deploy a test contract that utilizes TLOAD as
* part of its fallback logic.
*/
function _prepareTloadTest() private returns (address contractAddress) {
// Utilize assembly to deploy a contract testing TLOAD support.
assembly {
// Write the contract deployment code payload to scratch space.
mstore(0, _TLOAD_TEST_PAYLOAD)
// Deploy the contract.
contractAddress := create(
0,
_TLOAD_TEST_PAYLOAD_OFFSET,
_TLOAD_TEST_PAYLOAD_LENGTH
)
}
}
/**
* @dev Private view function to determine if TLOAD is supported by
* the current EVM implementation by attempting to call the test
* contract, which utilizes TLOAD as part of its fallback logic.
*/
function _testTload(
address tloadTestContract
) private view returns (bool ok) {
// Call the test contract, which will perform a TLOAD test. If the call
// does not revert, then TLOAD is supported. Do not forward all
// available gas, as all forwarded gas will be consumed on revert.
(ok, ) = tloadTestContract.staticcall{ gas: gasleft() / 10 }("");
}
}pragma solidity ^0.8.4;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}pragma solidity ^0.8.4;
import "../introspection/IERC165.sol";
interface IEOARegistry is IERC165 {
function isVerifiedEOA(address account) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
/**************************************************************/
/* LIST TYPES */
/**************************************************************/
uint8 constant LIST_TYPE_BLACKLIST = 0;
uint8 constant LIST_TYPE_WHITELIST = 1;
uint8 constant LIST_TYPE_AUTHORIZERS = 2;
uint8 constant EXPANSION_LIST_TYPE_WHITELIST_EXTENSION_CONTRACTS = 3;
uint8 constant EXPANSION_LIST_TYPE_7702_DELEGATE_WHITELIST = 4;
uint8 constant EXPANSION_LIST_TYPE_7702_DELEGATE_WHITELIST_EXTENSION_CONTRACTS = 5;
/**************************************************************/
/* RULESET IDS */
/**************************************************************/
uint8 constant RULESET_ID_DEFAULT = 0;
uint8 constant RULESET_ID_VANILLA = 1;
uint8 constant RULESET_ID_SOULBOUND = 2;
uint8 constant RULESET_ID_BLACKLIST = 3;
uint8 constant RULESET_ID_WHITELIST = 4;
uint8 constant RULESET_ID_FIXED_OR_CUSTOM = 255;
/**************************************************************/
/* AUTHORIZER CHECK TYPES */
/**************************************************************/
uint256 constant AUTHORIZER_CHECK_TYPE_TOKEN = 1;
uint256 constant AUTHORIZER_CHECK_TYPE_COLLECTION = 2;
uint256 constant AUTHORIZER_CHECK_TYPE_TOKEN_AND_AMOUNT = 3;
/**************************************************************/
/* MISCELLANEOUS */
/**************************************************************/
bytes4 constant LEGACY_TRANSFER_VALIDATOR_INTERFACE_ID = bytes4(0x00000000);
bytes4 constant SELECTOR_NO_ERROR = bytes4(0x00000000);
bytes32 constant BYTES32_ZERO = 0x0000000000000000000000000000000000000000000000000000000000000000;
bytes32 constant DEFAULT_ACCESS_CONTROL_ADMIN_ROLE = 0x0000000000000000000000000000000000000000000000000000000000000000;
address constant WILDCARD_OPERATOR_ADDRESS = address(0x01);
uint48 constant DEFAULT_LIST_ID = 0;
uint16 constant DEFAULT_TOKEN_TYPE = 0;
/**************************************************************/
/* FLAGS - GLOBAL */
/**************************************************************/
// Flags are used to efficiently store and retrieve boolean values in a single uint8.
// Each flag is a power of 2, so they can be combined using bitwise OR (|) and checked using bitwise AND (&).
// For example, to set the first and third flags, you would use: flags = FLAG1 | FLAG3;
// To check if the first flag is set, you would use: if (flags & FLAG1 != 0) { ... }
uint8 constant FLAG_GLOBAL_DISABLE_AUTHORIZATION_MODE = 1 << 0;
uint8 constant FLAG_GLOBAL_AUTHORIZERS_CANNOT_SET_WILDCARD_OPERATORS = 1 << 1;
uint8 constant FLAG_GLOBAL_ENABLE_ACCOUNT_FREEZING_MODE = 1 << 2;
uint8 constant FLAG_GLOBAL_CUSTOM_LIST_SUPPLEMENTS_DEFAULT_LIST = 1 << 3;
/**************************************************************/
/* FLAGS - RULESET WHITELIST */
/**************************************************************/
uint16 constant FLAG_RULESET_WHITELIST_BLOCK_ALL_OTC = 1 << 0;
uint16 constant FLAG_RULESET_WHITELIST_ALLOW_OTC_FOR_7702_DELEGATES = 1 << 1;
uint16 constant FLAG_RULESET_WHITELIST_ALLOW_OTC_FOR_SMART_WALLETS = 1 << 2;
uint16 constant FLAG_RULESET_WHITELIST_BLOCK_SMART_WALLET_RECEIVERS = 1 << 3;
uint16 constant FLAG_RULESET_WHITELIST_BLOCK_UNVERIFIED_EOA_RECEIVERS = 1 << 4;// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import "@limitbreak/tm-core-lib/src/utils/structs/EnumerableSet.sol";
/**
* @dev This struct contains the security policy settings for a collection.
*/
struct CollectionSecurityPolicy {
uint8 rulesetId;
uint48 listId;
address customRuleset;
uint8 globalOptions;
uint16 rulesetOptions;
uint16 tokenType;
}
/**
* @dev This struct is internally for the storage of account and codehash lists.
*/
struct List {
EnumerableSet.AddressSet enumerableAccounts;
EnumerableSet.Bytes32Set enumerableCodehashes;
mapping (address => bool) nonEnumerableAccounts;
mapping (bytes32 => bool) nonEnumerableCodehashes;
}
/**
* @dev This struct is internally for the storage of account lists.
*/
struct AccountList {
EnumerableSet.AddressSet enumerableAccounts;
mapping (address => bool) nonEnumerableAccounts;
}
/**
* @dev This struct contains a key and value pair for future expansion data words that are 32 bytes long.
*/
struct ExpansionWord {
bytes32 key;
bytes32 value;
}
/**
* @dev This struct contains a key and value pair for future expansion data bytes that are variable length.
*/
struct ExpansionDatum {
bytes32 key;
bytes value;
}
/**
* @dev This struct contains the storage layout for the validator contract, excluding Permit-C and Tstorish data.
*/
struct ValidatorStorage {
/// @notice Keeps track of the most recently created list id.
uint48 lastListId;
/// @dev Used as a collision guard.
mapping (address => address) transientOperator;
/// @notice Mapping of list ids to list owners
mapping (uint48 => address) listOwners;
/// @dev Mapping of collection addresses to their security policy settings
mapping (address => CollectionSecurityPolicy) collectionSecurityPolicies;
/// @dev Mapping of collections to accounts that are frozen for those collections
mapping (address => AccountList) frozenAccounts;
/// @dev Mapping of list ids to list data
mapping (uint8 => mapping (uint48 => List)) lists;
/// @dev Mapping of collection addressses to any future expansion data words settings that may be used in the future
mapping (address collection => mapping (bytes32 extension => bytes32 word)) collectionExpansionWords;
/// @dev Mapping of collection addressses to any future expansion data bytes settings that may be used in the future
mapping (address collection => mapping (bytes32 extension => bytes data)) collectionExpansionDatums;
/// @dev Mapping of addresses to a boolean indicating if they are registered trusted validator modules
mapping (address => bool) registeredRulesets;
/// @dev Mapping of security levels to their current implementation modules
mapping (uint8 => address) rulesetBindings;
}// SPDX-License-Identifier: MIT pragma solidity 0.8.24; /// @dev Thrown when admin attempts to bind a ruleset to the fixed/custom ruleset ID. error CreatorTokenTransferValidator__AdminCannotAssignRulesetToRulesetIdCustom(); /// @dev Thrown when validating transfers with amount if authorization by amount mode is active and the amount /// exceeds the pre-authorized amount. error CreatorTokenTransferValidator__AmountExceedsAuthorization(); /// @dev Thrown when attempting to set a authorized operator when authorization mode is disabled. error CreatorTokenTransferValidator__AuthorizationDisabledForCollection(); /// @dev Thrown when attempting to call a function that requires the caller to be the list owner. error CreatorTokenTransferValidator__CallerDoesNotOwnList(); /// @dev Thrown when authorizing a transfer for a collection using authorizers and the msg.sender is not in the /// authorizer list. error CreatorTokenTransferValidator__CallerMustBeAnAuthorizer(); /// @dev Thrown when validating a transfer for a collection using whitelists and the operator is not on the whitelist. error CreatorTokenTransferValidator__CallerMustBeWhitelisted(); /// @dev Thrown when attempting to call a function that requires owner or default admin role for a collection that the /// caller does not have. error CreatorTokenTransferValidator__CallerMustHaveElevatedPermissionsForSpecifiedNFT(); /// @dev Thrown when validating a transfer for a collection using whitelists and the operator or from account is not on the whitelist. error CreatorTokenTransferValidator__CallerOrFromMustBeWhitelisted(); /// @dev Thrown when attempting to renounce ownership of the default list id. error CreatorTokenTransferValidator__CannotRenounceOwnershipOfDefaultList(); /// @dev Thrown when setting the ruleset for a collection when a reserved ruleset id is used, but a custom ruleset /// is specified. error CreatorTokenTransferValidator__CannotSetCustomRulesetOnManagedRulesetId(); /// @dev Thrown when constructor args are not valid error CreatorTokenTransferValidator__InvalidConstructorArgs(); /// @dev Thrown when setting the transfer security level to an invalid value. error CreatorTokenTransferValidator__InvalidTransferSecurityLevel(); /// @dev Thrown when attempting to set a list id that does not exist. error CreatorTokenTransferValidator__ListDoesNotExist(); /// @dev Thrown when attempting to transfer the ownership of a list to the zero address. error CreatorTokenTransferValidator__ListOwnershipCannotBeTransferredToZeroAddress(); /// @dev Thrown when attempting to call the transfer validation logic externally, as staticcall guarantees are needed. error CreatorTokenTransferValidator__OnlyValidatorCanAccessThisFunction(); /// @dev Thrown when validating a transfer for a collection using blacklists and the operator is on the blacklist. error CreatorTokenTransferValidator__OperatorIsBlacklisted(); /// @dev Thrown when validating an OTC transfer with EIP-7702 Delegation when disabled by security settings. error CreatorTokenTransferValidator__OTCNotAllowedFor7702Delegates(); /// @dev Thrown when validating an OTC transfer from Smart Wallets when disabled by security settings. error CreatorTokenTransferValidator__OTCNotAllowedForSmartWallets(); /// @dev Thrown when a frozen account is the receiver of a transfer error CreatorTokenTransferValidator__ReceiverAccountIsFrozen(); /// @dev Thrown when validating a transfer for a collection that does not allow receiver to have code and the receiver /// has code. error CreatorTokenTransferValidator__ReceiverMustNotHaveDeployedCode(); /// @dev Thrown when validating a transfer for a collection that requires receivers be verified EOAs and the receiver /// is not verified. error CreatorTokenTransferValidator__ReceiverProofOfEOASignatureUnverified(); /// @dev Thrown when attempting to register a ruleset that is not a contract. error CreatorTokenTransferValidator__RulesetIsNotContract(); /// @dev Thrown when attempting to register a ruleset that is not pure. error CreatorTokenTransferValidator__RulesetIsNotPure(); /// @dev Thrown when admin attempts to bind a ruleset that is not registered, or a collection admin tries to /// set their fixed/custom ruleset to an unregistered ruleset. error CreatorTokenTransferValidator__RulesetIsNotRegistered(); /// @dev Thrown when a frozen account is the sender of a transfer error CreatorTokenTransferValidator__SenderAccountIsFrozen(); /// @dev Thrown when validating a transfer for a collection that is in soulbound token mode. error CreatorTokenTransferValidator__TokenIsSoulbound(); /// @dev Thrown when attempting to validate a permitted transfer where the permit type does not match the /// collection-defined token type. error CreatorTokenTransferValidator__TokenTypesDoNotMatch(); /// @dev Thrown when an authorizer attempts to set a wildcard authorized operator on collections that don't /// allow wildcards error CreatorTokenTransferValidator__WildcardOperatorsCannotBeAuthorizedForCollection();
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import "./DataTypes.sol";
import "./Errors.sol";
/**
* @title ValidatorBase
* @author Limit Break, Inc.
* @notice Base contract for all Creator Token Validator, Module, and Ruleset contracts.
* Includes some helper functions and modifiers and easy access to validator diamond storage
* to allow modules and rulesets to access the storage of the validator contract.
*/
contract ValidatorBase {
/*************************************************************************/
/* MODIFIERS */
/*************************************************************************/
/**
* @dev This modifier restricts a function call to the owner of the list `id`.
* @dev Throws when the caller is not the list owner.
*/
modifier onlyListOwner(uint48 id) {
_requireCallerOwnsList(id);
_;
}
/*************************************************************************/
/* HELPERS */
/*************************************************************************/
/**
* @notice Requires the caller to be the owner of list `id`.
*
* @dev Throws when the caller is not the owner of the list.
*
* @param id The id of the list to check ownership of.
*/
function _requireCallerOwnsList(uint48 id) private view {
if (msg.sender != validatorStorage().listOwners[id]) {
revert CreatorTokenTransferValidator__CallerDoesNotOwnList();
}
}
/**
* @dev Internal function used to compute the transient storage slot for the authorized
* operator of a token in a collection.
*
* @param collection The collection address of the token being transferred.
* @param tokenId The id of the token being transferred.
*
* @return operatorSlot The storage slot location for the authorized operator value.
*/
function _getTransientOperatorSlot(
address collection,
uint256 tokenId
) internal pure returns (uint256 operatorSlot) {
assembly {
mstore(0x00, collection)
mstore(0x20, tokenId)
operatorSlot := shr(4, keccak256(0x00, 0x40))
}
}
/**
* @dev Internal function used to compute the transient storage slot for the authorized operator of a collection.
*
* @param collection The collection address of the token being transferred.
*
* @return operatorSlot The storage slot location for the authorized operator value.
*/
function _getTransientOperatorSlot(address collection) internal view returns (uint256 operatorSlot) {
mapping (address => address) storage _transientOperator = validatorStorage().transientOperator;
assembly {
mstore(0x00, collection)
mstore(0x20, _transientOperator.slot)
operatorSlot := keccak256(0x00, 0x40)
}
}
/**
* @dev Internal function used to efficiently retrieve the code length of `account`.
*
* @param account The address to get the deployed code length for.
*
* @return length The length of deployed code at the address.
*/
function _getCodeLengthAsm(address account) internal view returns (uint256 length) {
assembly { length := extcodesize(account) }
}
/**
* @dev Internal function used to efficiently retrieve the codehash of `account`.
*
* @param account The address to get the deployed codehash for.
*
* @return codehash The codehash of the deployed code at the address.
*/
function _getCodeHashAsm(address account) internal view returns (bytes32 codehash) {
assembly { codehash := extcodehash(account) }
}
/**
* @notice Returns true if the `flagValue` has the `flag` set, false otherwise.
*
* @dev This function uses the bitwise AND operator to check if the `flag` is set in `flagValue`.
*
* @param flagValue The value to check for the presence of the `flag`.
* @param flag The flag to check for in the `flagValue`.
*/
function _isFlagSet(uint256 flagValue, uint256 flag) internal pure returns (bool flagSet) {
flagSet = (flagValue & flag) != 0;
}
/*************************************************************************/
/* STORAGE */
/*************************************************************************/
/// @dev The base storage slot for Validator V5 contract storage items.
bytes32 constant DIAMOND_STORAGE_VALIDATOR =
0x0000000000000000000000000000000000000000000000000000000000721C05;
/**
* @dev Returns a storage object that follows the Diamond standard storage pattern for
* @dev contract storage across multiple module contracts.
*/
function validatorStorage() internal pure returns (ValidatorStorage storage diamondStorage) {
bytes32 slot = DIAMOND_STORAGE_VALIDATOR;
assembly {
diamondStorage.slot := slot
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
/**
* @title IRuleset
* @author Limit Break, Inc.
* @notice Interface for Creator Token Standards ruleset contracts.
*
* @dev Ruleset contracts are logic-gate contracts used to validate transfers of Creator Tokens
* (ERC20-C / ERC721-C / ERC1155-C). Rulesets are view-only, and may not contain any opcodes
* that could modify the state of the blockchain.
*/
interface IRuleset {
/**
* @notice Validates a transfer of a Creator Token.
*
* @param authorizerCheckType The type of authorizer check to perform.
* @param collection The address of the Creator Token contract.
* @param caller The address of the caller (msg.sender) of the transfer function.
* @param from The address of the sender of the token.
* @param to The address of the recipient of the token.
* @param tokenId The ID of the token.
* @param amount The amount of the token to transfer.
* @return 0x00000000 when the transfer is allowed, or a custom error selector to block a transfer.
*/
function validateTransfer(
uint256 authorizerCheckType,
address collection,
address caller,
address from,
address to,
uint256 tokenId,
uint256 amount) external view returns (bytes4);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
/**
* @title IRuleset
* @author Limit Break, Inc.
* @notice Interface for whitelist extension contracts for the Whitelist Ruleset.
*
* @dev The Whitelist Ruleset supports whitelisting of specific accounts and codehashes.
* A Whitelist Extension contract offers an additional mechanism to perform more sophisticated
* checks to see if an account can be allowed to perform a transfer. For example, imagine a collection
* that blocks OTC transfers from smart wallet accounts because a smart wallet could be used to faciliate
* a trade that violates the creator's rules on trading. A Whitelist Extension contract could be used to
* query a trusted smart wallet factory that is known to adhere to the creator's rules, and allow any wallet
* originating from that factory to perform OTC trades or to receive tokens when in a mode that blocks contracts
* from receiving tokens.
*/
interface IWhitelistExtension {
/**
* @notice Perform an advanced check on an account to see if it should be whitelisted.
*
* @param collection The address of the Creator Token contract.
* @param account The address of the account to check.
* @return true if the account is whitelisted, false otherwise.
*/
function isWhitelisted(
address collection,
address account) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;
import "../Constants.sol";
import "../DataTypes.sol";
import "../Errors.sol";
import "../ValidatorBase.sol";
import "../interfaces/IRuleset.sol";
import "@limitbreak/tm-core-lib/src/utils/misc/Tloadish.sol";
/**
* @title RulesetBase
* @author Limit Break, Inc.
* @notice Base contract that includes internal helper functions and diamond storage access that are
* useful for implementations of Creator Token Standards ruleset contracts.
*/
abstract contract RulesetBase is ValidatorBase, Tloadish {
/**
* @dev Internal function to check if a caller is authorized to transfer a token/id/amount.
*
* @param authorizerCheckType The type of authorizer check to perform.
* @param collection The address of the Creator Token contract.
* @param caller The address of the caller (msg.sender) of the transfer function.
* @param tokenId The ID of the token.
* @param amount The amount of the token to transfer.
*
* @return isAuthorized True if the caller is authorized to transfer the token, false otherwise.
*/
function _isAuthorized(
uint256 authorizerCheckType,
address collection,
address caller,
uint256 tokenId,
uint256 amount
) internal view returns (bool isAuthorized) {
isAuthorized = _getAuthorizerCheckFunctionPointer(authorizerCheckType)(
collection, caller, tokenId, amount
);
}
/**
* @dev Internal function to get the function pointer for the authorizer check type.
*
* @param authorizerCheckType The type of authorizer check to perform.
*
* @return _callerAuthorizedCheck The function pointer to the authorizer check function.
*/
function _getAuthorizerCheckFunctionPointer(uint256 authorizerCheckType) internal pure returns (function(address,address,uint256, uint256) internal view returns(bool) _callerAuthorizedCheck) {
if (authorizerCheckType == AUTHORIZER_CHECK_TYPE_TOKEN) {
return _callerAuthorizedCheckToken;
} else if (authorizerCheckType == AUTHORIZER_CHECK_TYPE_COLLECTION) {
return _callerAuthorizedCheckCollection;
} else {
// The master validator handles the authorized amount check, so we won't do anything different here to use
// the authorized amount and the amount parameter.
// Current rulesets won't use this call, it is a placeholder for future ruleset use.
return _callerAuthorizedCheckCollection;
}
}
/**
* @dev Internal function to check if a caller is an authorized operator for the token being transferred.
*
* @param caller The caller of the token transfer.
* @param collection The collection address of the token being transferred.
* @param tokenId The id of the token being transferred.
*
* @return isAuthorized True if the caller is authorized to transfer the token, false otherwise.
*/
function _callerAuthorizedCheckToken(
address collection,
address caller,
uint256 tokenId,
uint256 /*amount*/
) internal view returns (bool isAuthorized) {
uint256 slotValue;
(isAuthorized, ) = _callerAuthorized(caller, _getTransientOperatorSlot(collection, tokenId));
if (isAuthorized) return true;
(isAuthorized, slotValue) = _callerAuthorized(caller, _getTransientOperatorSlot(collection));
isAuthorized = isAuthorized && slotValue >> 255 == 1;
}
/**
* @dev Internal function to check if a caller is an authorized operator for the collection being transferred.
*
* @param caller The caller of the token transfer.
* @param collection The collection address of the token being transferred.
*
* @return isAuthorized True if the caller is authorized to transfer the collection, false otherwise.
*/
function _callerAuthorizedCheckCollection(
address collection,
address caller,
uint256 /*tokenId*/,
uint256 /*amount*/
) internal view returns (bool isAuthorized) {
(isAuthorized, ) = _callerAuthorized(caller, _getTransientOperatorSlot(collection));
}
/**
* @dev Internal function to check if a caller is an authorized operator.
* @dev This overload of `_callerAuthorized` checks a specific storage slot for the caller address.
*
* @param caller The caller of the token transfer.
* @param slot The storage slot to check for the caller address.
*
* @return isAuthorized True if the caller is authorized to transfer the token, false otherwise.
* @return slotValue The transient storage value in `slot`, used to check for allow any token id flag if necessary.
*/
function _callerAuthorized(address caller, uint256 slot) internal view returns (bool isAuthorized, uint256 slotValue) {
slotValue = _getTstorish(slot);
address authorizedOperator = address(uint160(slotValue));
isAuthorized = authorizedOperator == WILDCARD_OPERATOR_ADDRESS || authorizedOperator == caller;
}
/**
* @dev Internal function to check if an address is an EOA in EIP-7702 delegation mode, and what address
* it is delegated to.
*
* @param _address The account to check for EIP-7702 delegation.
*
* @return isDelegate True if the account is an EOA with an EIP-7702 delegate attached, false otherwise.
* @return delegate The address of the EIP-7702 delegate code, if one is attached.
*/
function _check7702(address _address) internal view returns (bool isDelegate, address delegate) {
assembly ("memory-safe") {
mstore(0x00, 0x00)
extcodecopy(_address, 0x1D, 0x00, 0x17)
if eq(mload(0x00), 0xEF0100) {
isDelegate := 1
delegate := shr(0x60, mload(0x20))
}
}
}
}{
"remappings": [
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"@limitbreak/tm-core-lib/=lib/tm-core-lib/",
"@limitbreak/permit-c/=lib/PermitC/src/",
"@openzeppelin/=lib/PermitC/lib/openzeppelin-contracts/",
"@rari-capital/solmate/=lib/PermitC/lib/solmate/",
"PermitC/=lib/PermitC/",
"erc4626-tests/=lib/PermitC/lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-gas-metering/=lib/PermitC/lib/forge-gas-metering/",
"openzeppelin-contracts/=lib/PermitC/lib/openzeppelin-contracts/",
"openzeppelin/=lib/PermitC/lib/openzeppelin-contracts/contracts/",
"solady/=lib/PermitC/lib/forge-gas-metering/lib/solady/",
"solmate/=lib/PermitC/lib/solmate/src/",
"tm-core-lib/=lib/tm-core-lib/src/"
],
"optimizer": {
"enabled": true,
"runs": 1000000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": false
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"eoaRegistry_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CreatorTokenTransferValidator__InvalidConstructorArgs","type":"error"},{"inputs":[],"name":"TloadTestContractDeploymentFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"authorizerCheckType","type":"uint256"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"validateTransfer","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"}]Contract Creation Code
61010060405234801562000011575f80fd5b5060405162001164380380620011648339810160408190526200003491620001dc565b5f6200003f62000127565b90506001600160a01b0381166200006957604051632aea588760e01b815260040160405180910390fd5b620000748162000140565b7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b00805460ff19169115801592831790915560a091909152620000ce576001600160401b0362000277620001a260201b171660c052620000e7565b6001600160401b036200027b620001a660201b171660c0525b6001600160a01b039081166080528116620001155760405163c56e5d7360e01b815260040160405180910390fd5b6001600160a01b031660e0526200022b565b5f696002601e613d5c3d52f35f52600a60165ff0905090565b5f816001600160a01b0316600a5a6200015a91906200020b565b6040515f8181818686fa925050503d805f811462000194576040519150601f19603f3d011682016040523d82523d5f602084013e62000199565b606091505b50909392505050565b5c90565b5f7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff1615620001d757505c90565b505490565b5f60208284031215620001ed575f80fd5b81516001600160a01b038116811462000204575f80fd5b9392505050565b5f826200022657634e487b7160e01b5f52601260045260245ffd5b500490565b60805160a05160c05160e051610f0b620002595f395f6106c901525f610d3401525f50505f5050610f0b5ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80630be200ea1461002d575b5f80fd5b61004061003b366004610e26565b610075565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b73ffffffffffffffffffffffffffffffffffffffff86165f90815262721c08602052604081208054829061014f9060ff7b010000000000000000000000000000000000000000000000000000008204169061ffff7c01000000000000000000000000000000000000000000000000000000009091041660408051610100810182526004848116151582526001808616151560208401526008958616151593830193909352938316151560608201526010831615156080820152908216151560a082015260028216151560c08201529116151560e082015290565b8051909150156102235773ffffffffffffffffffffffffffffffffffffffff8981165f90815262721c0960209081526040808320938b1683526002840190915290205460ff16156101c657507f2b635c8800000000000000000000000000000000000000000000000000000000925061026c915050565b73ffffffffffffffffffffffffffffffffffffffff87165f90815260028201602052604090205460ff161561022157507f2a5cb1c300000000000000000000000000000000000000000000000000000000925061026c915050565b505b8060200151610249576102398a8a8a88886102b4565b1561024957505f915061026c9050565b8154610267908290610100900465ffffffffffff168b898c8c6102d7565b925050505b979650505050505050565b5c90565b5f7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff16156102ab57505c90565b5080545b919050565b5f6102cd858585856102c58b610594565b63ffffffff16565b9695505050505050565b65ffffffffffff85165f9081527fdddabf5c2ba4d65801ab32cdb63ad695571faeb901010108d1a350518718439e602090815260408083207f2841ea725888be53292047902c89cc990fdbb15dbc2e5b558a6a052c722a0ede90925282206060890151600483019260050191901561039257863b15610392576103628a604001518484848c8c6105c2565b61039257507faca58aa00000000000000000000000000000000000000000000000000000000092506102cd915050565b8960800151156103eb576103a587610682565b6103eb576103bb8a604001518484848c8c6105c2565b6103eb57507fce32f2aa0000000000000000000000000000000000000000000000000000000092506102cd915050565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1603610542578960a0015161054257843b15610536575f806104398761073a565b915091508b60c001511561049e5781610499578b60e00151610499576104678c604001518686868e8c6105c2565b61049957507f42d0e0e40000000000000000000000000000000000000000000000000000000094506102cd9350505050565b610533565b81156104e6576104b48c604001518c8c84610762565b61049957507f369c2f4c0000000000000000000000000000000000000000000000000000000094506102cd9350505050565b8b60e00151610533576105018c604001518686868e8c6105c2565b61053357507f42d0e0e40000000000000000000000000000000000000000000000000000000094506102cd9350505050565b50505b505f92506102cd915050565b6105558a604001518484848c8b8b610898565b61058557507fe1f1d02e0000000000000000000000000000000000000000000000000000000092506102cd915050565b505f9998505050505050505050565b610df9600182036105a85750610966919050565b600282036105b957506109d3919050565b506109d3919050565b5f8615610675575f80527f2841ea725888be53292047902c89cc990fdbb15dbc2e5b558a6a052c722a0ede6020527f938cff0dbdc4b4032da5e0e3a4947fb40aba826911a8ad09a80c555fd5830d5b7f938cff0dbdc4b4032da5e0e3a4947fb40aba826911a8ad09a80c555fd5830d5c7fe6367c6c33ddbb3b5b8a8c588253bb03f885a3f85345efae1611865a80acc52361066083838389896109f7565b1561067157600193505050506102cd565b5050505b61026c86868686866109f7565b6040517f89a9c85500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301525f917f0000000000000000000000000000000000000000000000000000000000000000909116906389a9c85590602401602060405180830381865afa158015610710573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107349190610e92565b92915050565b5f805f805260175f601d853c62ef01005f510361075d57505060205160019060601c5b915091565b5f8415610815575f80527fe91a6628aa83f010ff9afa7f160b18736f245c1821f24ffae38c046526028eb16020527f739a1fa67523b96335a4175253d835d43315604e3ab95d6deb68d9488a6242f17f739a1fa67523b96335a4175253d835d43315604e3ab95d6deb68d9488a6242f27fa731cdb379c53870826417699a62d8514fe9e04ae3343c38d8e6940d1ccb6bca61080083838389896109f7565b156108115760019350505050610890565b5050505b65ffffffffffff84165f9081527f5e58bed0817b31bdcd1d55e32930f39f8107eac1d4c0fd8dbef0c8c7e7389b6f602090815260408083207fe91a6628aa83f010ff9afa7f160b18736f245c1821f24ffae38c046526028eb190925290912060048201916005019061088a83838389896109f7565b93505050505b949350505050565b5f871561094c575f80527f2841ea725888be53292047902c89cc990fdbb15dbc2e5b558a6a052c722a0ede6020527f938cff0dbdc4b4032da5e0e3a4947fb40aba826911a8ad09a80c555fd5830d5b7f938cff0dbdc4b4032da5e0e3a4947fb40aba826911a8ad09a80c555fd5830d5c7fe6367c6c33ddbb3b5b8a8c588253bb03f885a3f85345efae1611865a80acc5236109378383838a8a8a610b1f565b15610948576001935050505061026c565b5050505b61095a878787878787610b1f565b98975050505050505050565b5f806109878561098288875f9182526020526040902060041c90565b610d2c565b509150811561099a576001915050610890565b6109b485610982885f90815262721c066020526040902090565b90925090508180156102cd575060ff81901c6001149695505050505050565b5f84815262721c06602052604081206109ed908590610d2c565b5095945050505050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526020869052604081205460ff1680610a395750813f5f9081526020869052604090205460ff165b905080610b16575f610a4a85610db8565b90505f5b81811015610b13575f610a618783610dc1565b6040517fb6b3527200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015287811660248301529192509082169063b6b3527290604401602060405180830381865afa158015610ad7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610afb9190610e92565b15610b0a576001935050610b13565b50600101610a4e565b50505b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526020879052604081205460ff1680610b76575073ffffffffffffffffffffffffffffffffffffffff82165f9081526020889052604090205460ff165b80610b905750823f5f9081526020879052604090205460ff165b80610baa5750813f5f9081526020879052604090205460ff165b9050806102cd575f610bbb86610db8565b90505f5b81811015610d20575f610bd28883610dc1565b6040517fb6b3527200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff898116600483015288811660248301529192509082169063b6b3527290604401602060405180830381865afa158015610c48573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c6c9190610e92565b80610d0857506040517fb6b3527200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152868116602483015282169063b6b3527290604401602060405180830381865afa158015610ce4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d089190610e92565b15610d17576001935050610d20565b50600101610bbf565b50509695505050505050565b5f80610d5b837f000000000000000000000000000000000000000000000000000000000000000063ffffffff16565b90508073ffffffffffffffffffffffffffffffffffffffff811660011480610dae57508473ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b9250509250929050565b5f610734825490565b5f610dcc8383610dd3565b9392505050565b5f825f018281548110610de857610de8610eb1565b905f5260205f200154905092915050565b610e01610ede565b565b803573ffffffffffffffffffffffffffffffffffffffff811681146102af575f80fd5b5f805f805f805f60e0888a031215610e3c575f80fd5b87359650610e4c60208901610e03565b9550610e5a60408901610e03565b9450610e6860608901610e03565b9350610e7660808901610e03565b925060a0880135915060c0880135905092959891949750929550565b5f60208284031215610ea2575f80fd5b81518015158114610dcc575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52605160045260245ffd000000000000000000000000e0a0004dfa318fc38298ae81a666710eadceba5c
Deployed Bytecode
0x608060405234801561000f575f80fd5b5060043610610029575f3560e01c80630be200ea1461002d575b5f80fd5b61004061003b366004610e26565b610075565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b73ffffffffffffffffffffffffffffffffffffffff86165f90815262721c08602052604081208054829061014f9060ff7b010000000000000000000000000000000000000000000000000000008204169061ffff7c01000000000000000000000000000000000000000000000000000000009091041660408051610100810182526004848116151582526001808616151560208401526008958616151593830193909352938316151560608201526010831615156080820152908216151560a082015260028216151560c08201529116151560e082015290565b8051909150156102235773ffffffffffffffffffffffffffffffffffffffff8981165f90815262721c0960209081526040808320938b1683526002840190915290205460ff16156101c657507f2b635c8800000000000000000000000000000000000000000000000000000000925061026c915050565b73ffffffffffffffffffffffffffffffffffffffff87165f90815260028201602052604090205460ff161561022157507f2a5cb1c300000000000000000000000000000000000000000000000000000000925061026c915050565b505b8060200151610249576102398a8a8a88886102b4565b1561024957505f915061026c9050565b8154610267908290610100900465ffffffffffff168b898c8c6102d7565b925050505b979650505050505050565b5c90565b5f7fdacd49f6a6c42b45a5c3d195b83b324104542d9147bb8064a39c6a8d23ba9b005460ff16156102ab57505c90565b5080545b919050565b5f6102cd858585856102c58b610594565b63ffffffff16565b9695505050505050565b65ffffffffffff85165f9081527fdddabf5c2ba4d65801ab32cdb63ad695571faeb901010108d1a350518718439e602090815260408083207f2841ea725888be53292047902c89cc990fdbb15dbc2e5b558a6a052c722a0ede90925282206060890151600483019260050191901561039257863b15610392576103628a604001518484848c8c6105c2565b61039257507faca58aa00000000000000000000000000000000000000000000000000000000092506102cd915050565b8960800151156103eb576103a587610682565b6103eb576103bb8a604001518484848c8c6105c2565b6103eb57507fce32f2aa0000000000000000000000000000000000000000000000000000000092506102cd915050565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1603610542578960a0015161054257843b15610536575f806104398761073a565b915091508b60c001511561049e5781610499578b60e00151610499576104678c604001518686868e8c6105c2565b61049957507f42d0e0e40000000000000000000000000000000000000000000000000000000094506102cd9350505050565b610533565b81156104e6576104b48c604001518c8c84610762565b61049957507f369c2f4c0000000000000000000000000000000000000000000000000000000094506102cd9350505050565b8b60e00151610533576105018c604001518686868e8c6105c2565b61053357507f42d0e0e40000000000000000000000000000000000000000000000000000000094506102cd9350505050565b50505b505f92506102cd915050565b6105558a604001518484848c8b8b610898565b61058557507fe1f1d02e0000000000000000000000000000000000000000000000000000000092506102cd915050565b505f9998505050505050505050565b610df9600182036105a85750610966919050565b600282036105b957506109d3919050565b506109d3919050565b5f8615610675575f80527f2841ea725888be53292047902c89cc990fdbb15dbc2e5b558a6a052c722a0ede6020527f938cff0dbdc4b4032da5e0e3a4947fb40aba826911a8ad09a80c555fd5830d5b7f938cff0dbdc4b4032da5e0e3a4947fb40aba826911a8ad09a80c555fd5830d5c7fe6367c6c33ddbb3b5b8a8c588253bb03f885a3f85345efae1611865a80acc52361066083838389896109f7565b1561067157600193505050506102cd565b5050505b61026c86868686866109f7565b6040517f89a9c85500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301525f917f000000000000000000000000e0a0004dfa318fc38298ae81a666710eadceba5c909116906389a9c85590602401602060405180830381865afa158015610710573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107349190610e92565b92915050565b5f805f805260175f601d853c62ef01005f510361075d57505060205160019060601c5b915091565b5f8415610815575f80527fe91a6628aa83f010ff9afa7f160b18736f245c1821f24ffae38c046526028eb16020527f739a1fa67523b96335a4175253d835d43315604e3ab95d6deb68d9488a6242f17f739a1fa67523b96335a4175253d835d43315604e3ab95d6deb68d9488a6242f27fa731cdb379c53870826417699a62d8514fe9e04ae3343c38d8e6940d1ccb6bca61080083838389896109f7565b156108115760019350505050610890565b5050505b65ffffffffffff84165f9081527f5e58bed0817b31bdcd1d55e32930f39f8107eac1d4c0fd8dbef0c8c7e7389b6f602090815260408083207fe91a6628aa83f010ff9afa7f160b18736f245c1821f24ffae38c046526028eb190925290912060048201916005019061088a83838389896109f7565b93505050505b949350505050565b5f871561094c575f80527f2841ea725888be53292047902c89cc990fdbb15dbc2e5b558a6a052c722a0ede6020527f938cff0dbdc4b4032da5e0e3a4947fb40aba826911a8ad09a80c555fd5830d5b7f938cff0dbdc4b4032da5e0e3a4947fb40aba826911a8ad09a80c555fd5830d5c7fe6367c6c33ddbb3b5b8a8c588253bb03f885a3f85345efae1611865a80acc5236109378383838a8a8a610b1f565b15610948576001935050505061026c565b5050505b61095a878787878787610b1f565b98975050505050505050565b5f806109878561098288875f9182526020526040902060041c90565b610d2c565b509150811561099a576001915050610890565b6109b485610982885f90815262721c066020526040902090565b90925090508180156102cd575060ff81901c6001149695505050505050565b5f84815262721c06602052604081206109ed908590610d2c565b5095945050505050565b73ffffffffffffffffffffffffffffffffffffffff81165f9081526020869052604081205460ff1680610a395750813f5f9081526020869052604090205460ff165b905080610b16575f610a4a85610db8565b90505f5b81811015610b13575f610a618783610dc1565b6040517fb6b3527200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff888116600483015287811660248301529192509082169063b6b3527290604401602060405180830381865afa158015610ad7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610afb9190610e92565b15610b0a576001935050610b13565b50600101610a4e565b50505b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff82165f9081526020879052604081205460ff1680610b76575073ffffffffffffffffffffffffffffffffffffffff82165f9081526020889052604090205460ff165b80610b905750823f5f9081526020879052604090205460ff165b80610baa5750813f5f9081526020879052604090205460ff165b9050806102cd575f610bbb86610db8565b90505f5b81811015610d20575f610bd28883610dc1565b6040517fb6b3527200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff898116600483015288811660248301529192509082169063b6b3527290604401602060405180830381865afa158015610c48573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c6c9190610e92565b80610d0857506040517fb6b3527200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152868116602483015282169063b6b3527290604401602060405180830381865afa158015610ce4573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d089190610e92565b15610d17576001935050610d20565b50600101610bbf565b50509695505050505050565b5f80610d5b837f000000000000000000000000000000000000000000000000000001a20000027763ffffffff16565b90508073ffffffffffffffffffffffffffffffffffffffff811660011480610dae57508473ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b9250509250929050565b5f610734825490565b5f610dcc8383610dd3565b9392505050565b5f825f018281548110610de857610de8610eb1565b905f5260205f200154905092915050565b610e01610ede565b565b803573ffffffffffffffffffffffffffffffffffffffff811681146102af575f80fd5b5f805f805f805f60e0888a031215610e3c575f80fd5b87359650610e4c60208901610e03565b9550610e5a60408901610e03565b9450610e6860608901610e03565b9350610e7660808901610e03565b925060a0880135915060c0880135905092959891949750929550565b5f60208284031215610ea2575f80fd5b81518015158114610dcc575f80fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52605160045260245ffd
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000e0a0004dfa318fc38298ae81a666710eadceba5c
-----Decoded View---------------
Arg [0] : eoaRegistry_ (address): 0xE0A0004Dfa318fc38298aE81a666710eaDCEba5C
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000e0a0004dfa318fc38298ae81a666710eadceba5c
Deployed Bytecode Sourcemap
418:19776:12:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6531:1410;;;;;;:::i;:::-;;:::i;:::-;;;1010:66:13;998:79;;;980:98;;968:2;953:18;6531:1410:12;;;;;;;;6853:57;;;6762:6;6853:57;;;:45;:57;;;;;6968:38;;6762:6;;6956:92;;6968:38;;;;;;7008:39;;;;;;-1:-1:-1;;;;;;;;2858:6:5;4361:16:8;;;4360:23;;17750:116:12;;2713:6:5;4361:16:8;;;4360:23;;-1:-1:-1;;;17877:113:12;2932:6:5;4361:16:8;;;4360:23;;-1:-1:-1;;;18001:131:12;;;;4361:16:8;;;4360:23;;-1:-1:-1;;;18143:130:12;3505:6:5;4361:16:8;;4360:23;;-1:-1:-1;;;18284:134:12;4361:16:8;;;4360:23;;-1:-1:-1;;;18429:101:12;3270:6:5;4361:16:8;;4360:23;;-1:-1:-1;;;18541:129:12;4361:16:8;;4360:23;;-1:-1:-1;;;18693:127:12;-1:-1:-1;17626:1201:12;6956:92;7063:30;;6921:127;;-1:-1:-1;7059:490:12;;;7149:45;;;;7109:37;7149:45;;;:33;:45;;;;;;;;7225;;;;;:39;;;:45;;;;;;;;7221:152;;;-1:-1:-1;7297:61:12;;-1:-1:-1;7290:68:12;;-1:-1:-1;;7290:68:12;7221:152;7391:43;;;;;;;:39;;;:43;;;;;;;;7387:152;;;-1:-1:-1;7461:63:12;;-1:-1:-1;7454:70:12;;-1:-1:-1;;7454:70:12;7387:152;7095:454;7059:490;7564:4;:29;;;7559:194;;7613:71;7627:19;7648:10;7660:6;7668:7;7677:6;7613:13;:71::i;:::-;7609:134;;;-1:-1:-1;1720:10:5;;-1:-1:-1;7704:24:12;;-1:-1:-1;7704:24:12;7609:134;7821:31;;7770:164;;7802:4;;7821:31;;;;;7866:10;7891:2;7908:6;7929:4;7770:18;:164::i;:::-;7763:171;;;;6531:1410;;;;;;;;;;:::o;3690:169:2:-;3825:18;;3690:169::o;4236:360::-;4333:13;212:66:1;4362:36:2;;;4358:232;;;-1:-1:-1;4450:18:2;;4236:360::o;4358:232::-;-1:-1:-1;4548:18:2;;4358:232;4236:360;;;:::o;1183:356:11:-;1374:17;1418:114;1487:10;1499:6;1507:7;1516:6;1418:55;1453:19;1418:34;:55::i;:::-;:114;;:::i;:::-;1403:129;1183:356;-1:-1:-1;;;;;;1183:356:11:o;7947:3784:12:-;19148:53;;;8151:6;19148:53;;;:45;;:53;;;:45;:53;;;19369:75;:83;;;;;8428:30;;;;19230:31;;;;19148:24;19291:33;;19369:83;8424:376;;;3444:20:8;;8478:25:12;8474:316;;8528:127;8543:4;:37;;;8582:16;8600:17;8619:19;8640:10;8652:2;8528:14;:127::i;:::-;8523:253;;-1:-1:-1;8686:71:12;;-1:-1:-1;8679:78:12;;-1:-1:-1;;8679:78:12;8523:253;8814:4;:32;;;8810:378;;;8867:18;8882:2;8867:14;:18::i;:::-;8862:316;;8910:127;8925:4;:37;;;8964:16;8982:17;9001:19;9022:10;9034:2;8910:14;:127::i;:::-;8905:259;;-1:-1:-1;9068:77:12;;-1:-1:-1;9061:84:12;;-1:-1:-1;;9061:84:12;8905:259;9212:4;9202:14;;:6;:14;;;9198:2237;;9237:4;:16;;;9232:2193;;3444:20:8;;9277:27:12;9273:2095;;9329:15;9346:16;9366;9377:4;9366:10;:16::i;:::-;9328:54;;;;9409:4;:29;;;9405:1945;;;9573:10;9568:597;;9761:4;:28;;;9756:383;;9830:129;9845:4;:37;;;9884:16;9902:17;9921:19;9942:10;9954:4;9830:14;:129::i;:::-;9825:284;;-1:-1:-1;10006:68:12;;-1:-1:-1;9999:75:12;;-1:-1:-1;;;;9999:75:12;9825:284;9405:1945;;;10329:10;10325:1003;;;10478:95;10505:4;:37;;;10544:6;10552:10;10564:8;10478:26;:95::i;:::-;10473:243;;-1:-1:-1;10616:69:12;;-1:-1:-1;10609:76:12;;-1:-1:-1;;;;10609:76:12;10325:1003;10924:4;:28;;;10919:383;;10993:129;11008:4;:37;;;11047:16;11065:17;11084:19;11105:10;11117:4;10993:14;:129::i;:::-;10988:284;;-1:-1:-1;11169:68:12;;-1:-1:-1;11162:75:12;;-1:-1:-1;;;;11162:75:12;10988:284;9306:2062;;9273:2095;-1:-1:-1;1720:10:5;;-1:-1:-1;11386:24:12;;-1:-1:-1;;11386:24:12;9232:2193;11450:137;11465:4;:37;;;11504:16;11522:17;11541:19;11562:10;11574:6;11582:4;11450:14;:137::i;:::-;11445:245;;-1:-1:-1;11610:69:12;;-1:-1:-1;11603:76:12;;-1:-1:-1;;11603:76:12;11445:245;-1:-1:-1;1720:10:5;;7947:3784:12;-1:-1:-1;;;;;;;;;7947:3784:12:o;1835:802:11:-;1931:93;1284:1:5;2040:19:11;:50;2036:595;;-1:-1:-1;2113:27:11;;1835:802;-1:-1:-1;1835:802:11:o;2036:595::-;1339:1:5;2161:19:11;:55;2157:474;;-1:-1:-1;2239:32:11;;1835:802;-1:-1:-1;1835:802:11:o;2157:474::-;-1:-1:-1;2588:32:11;;1835:802;-1:-1:-1;1835:802:11:o;11737:1121:12:-;12073:18;12107:32;12103:637;;;12173:57;19148:53;;19369:75;19148:45;19369:83;19230:31;19291:33;19369:83;12464:220;19230:31;19291:33;19369:83;12643:10;12676:7;12464:15;:220::i;:::-;12460:270;;;12711:4;12704:11;;;;;;;12460:270;12141:599;;;12103:637;12757:94;12773:16;12791:17;12810:19;12831:10;12843:7;12757:15;:94::i;17477:143::-;17564:49;;;;;:40;1253:55:13;;;17564:49:12;;;1235:74:13;17541:4:12;;17577:12;17564:40;;;;;;1208:18:13;;17564:49:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;17557:56;17477:143;-1:-1:-1;;17477:143:12:o;5681:371:11:-;5742:15;5759:16;5839:4;5833;5826:18;5891:4;5885;5879;5869:8;5857:39;5928:8;5921:4;5915:11;5912:25;5909:127;;-1:-1:-1;;6016:4:11;6010:11;5970:1;;6004:4;6000:22;5909:127;5681:371;;;:::o;14060:1252:12:-;14248:18;14282:32;14278:649;;;14348:57;19824:77;;20069:89;19824:69;20069:97;19930:31;19991:33;20069:97;14651:220;19930:31;19991:33;20069:97;14830:10;14863:7;14651:15;:220::i;:::-;14647:270;;;14898:4;14891:11;;;;;;;14647:270;14316:611;;;14278:649;19824:77;;;14951:50;19824:77;;;:69;;:77;;;:69;:77;;;20069:89;:97;;;;;;506:1:5;19930:31:12;;;19824:24;19991:33;;15211:94;19930:31;19991:33;20069:97;15285:10;15297:7;15211:15;:94::i;:::-;15204:101;;;;;14060:1252;;;;;;;:::o;12864:1190::-;13227:18;13261:32;13257:668;;;13327:57;19148:53;;19369:75;19148:45;19369:83;19230:31;19291:33;19369:83;13618:251;19230:31;19291:33;19369:83;13797:10;13830:8;13860;13618:15;:251::i;:::-;13614:301;;;13896:4;13889:11;;;;;;;13614:301;13295:630;;;13257:668;13942:105;13958:16;13976:17;13995:19;14016:10;14028:8;14038;13942:15;:105::i;:::-;13935:112;12864:1190;-1:-1:-1;;;;;;;;12864:1190:12:o;3090:529:11:-;3261:17;3290;3336:73;3354:6;3362:46;3388:10;3400:7;2178:20:8;2233:24;;;2277:4;2270:21;2343:4;2327:21;;2324:1;2320:29;;2060:304;3362:46:11;3336:17;:73::i;:::-;-1:-1:-1;3317:92:11;-1:-1:-1;3419:29:11;;;;3444:4;3437:11;;;;;3419:29;3486:64;3504:6;3512:37;3538:10;2767:20:8;2926:24;;;2857:36;2970:4;2963:37;3045:4;3029:21;;;2689:377;3486:64:11;3458:92;;-1:-1:-1;3458:92:11;-1:-1:-1;3458:92:11;3575:37;;;;;3604:3;3591:9;:16;;3611:1;3591:21;3560:52;3090:529;-1:-1:-1;;;;;;3090:529:11:o;4018:299::-;4198:17;2926:24:8;;;2857:36;2970:4;2963:37;3045:4;3029:21;;4246:64:11;;4264:6;;3336:17;:73::i;4246:64::-;-1:-1:-1;4227:83:11;4018:299;-1:-1:-1;;;;;4018:299:11:o;15318:915:12:-;15671:25;;;15608:18;15671:25;;;;;;;;;;;;;;:89;;-1:-1:-1;3854:20:8;;15717:43:12;;;;;;;;;;;;;;15671:89;15638:122;;15776:13;15771:456;;15805:30;15838:28;:19;:26;:28::i;:::-;15805:61;;15885:9;15880:337;15904:22;15900:1;:26;15880:337;;;15951:38;16012:25;:19;16035:1;16012:22;:25::i;:::-;16060:53;;;;;:32;1855:15:13;;;16060:53:12;;;1837:34:13;1907:15;;;1887:18;;;1880:43;15951:87:12;;-1:-1:-1;16060:32:12;;;;;;1749:18:13;;16060:53:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;16056:147;;;16153:4;16137:20;;16179:5;;;16056:147;-1:-1:-1;15928:3:12;;15880:337;;;;15791:436;15771:456;15318:915;;;;;;;:::o;16239:1119::-;16615:26;;;16556:18;16615:26;;;;;;;;;;;;;;:69;;-1:-1:-1;16658:26:12;;;;;;;;;;;;;;;;;16615:69;:130;;;-1:-1:-1;3854:20:8;;16701:44:12;;;;;;;;;;;;;;16615:130;:190;;;-1:-1:-1;3854:20:8;;16761:44:12;;;;;;;;;;;;;;16615:190;16586:219;;16821:13;16816:536;;16850:30;16883:28;:19;:26;:28::i;:::-;16850:61;;16930:9;16925:417;16949:22;16945:1;:26;16925:417;;;16996:38;17057:25;:19;17080:1;17057:22;:25::i;:::-;17105:54;;;;;:32;1855:15:13;;;17105:54:12;;;1837:34:13;1907:15;;;1887:18;;;1880:43;16996:87:12;;-1:-1:-1;17105:32:12;;;;;;1749:18:13;;17105:54:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:133;;;-1:-1:-1;17184:54:12;;;;;:32;1855:15:13;;;17184:54:12;;;1837:34:13;1907:15;;;1887:18;;;1880:43;17184:32:12;;;;;1749:18:13;;17184:54:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;17101:227;;;17278:4;17262:20;;17304:5;;;17101:227;-1:-1:-1;16973:3:12;;16925:417;;;;16836:516;16239:1119;;;;;;;;:::o;4898:335:11:-;4978:17;4997;5038:18;5051:4;5038:12;:18;;:::i;:::-;5026:30;-1:-1:-1;5026:30:11;5147:47;;;2007:4:5;5147:47:11;;:79;;;5220:6;5198:28;;:18;:28;;;5147:79;5132:94;;5016:217;4898:335;;;;;:::o;8911:115:3:-;8974:7;9000:19;9008:3;4350:18;;4268:107;9368:156;9442:7;9492:22;9496:3;9508:5;9492:3;:22::i;:::-;9484:31;9368:156;-1:-1:-1;;;9368:156:3:o;4717:118::-;4784:7;4810:3;:11;;4822:5;4810:18;;;;;;;;:::i;:::-;;;;;;;;;4803:25;;4717:118;;;;:::o;-1:-1:-1:-;;;:::i;:::-;:::o;14:196:13:-;82:20;;142:42;131:54;;121:65;;111:93;;200:1;197;190:12;215:616;328:6;336;344;352;360;368;376;429:3;417:9;408:7;404:23;400:33;397:53;;;446:1;443;436:12;397:53;482:9;469:23;459:33;;511:38;545:2;534:9;530:18;511:38;:::i;:::-;501:48;;568:38;602:2;591:9;587:18;568:38;:::i;:::-;558:48;;625:38;659:2;648:9;644:18;625:38;:::i;:::-;615:48;;682:39;716:3;705:9;701:19;682:39;:::i;:::-;672:49;;768:3;757:9;753:19;740:33;730:43;;820:3;809:9;805:19;792:33;782:43;;215:616;;;;;;;;;;:::o;1320:277::-;1387:6;1440:2;1428:9;1419:7;1415:23;1411:32;1408:52;;;1456:1;1453;1446:12;1408:52;1488:9;1482:16;1541:5;1534:13;1527:21;1520:5;1517:32;1507:60;;1563:1;1560;1553:12;1934:184;1986:77;1983:1;1976:88;2083:4;2080:1;2073:15;2107:4;2104:1;2097:15;2123:184;2175:77;2172:1;2165:88;2272:4;2269:1;2262:15;2296:4;2293:1;2286:15
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in MON
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.