// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)pragmasolidity ^0.8.1;/**
* @dev Collection of functions related to the address type
*/libraryAddress{
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/functionisContract(address account) internalviewreturns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0// for contracts in construction, since the code is only stored at the end// of the constructor execution.return account.code.length>0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/functionsendValue(addresspayable recipient, uint256 amount) internal{
require(address(this).balance>= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/functionfunctionCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/functionfunctionCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/functionfunctionCallWithValue(address target, bytesmemory data, uint256 value) internalreturns (bytesmemory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/functionfunctionCallWithValue(address target,
bytesmemory data,
uint256 value,
stringmemory errorMessage
) internalreturns (bytesmemory) {
require(address(this).balance>= value, "Address: insufficient balance for call");
(bool success, bytesmemory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/functionfunctionStaticCall(address target, bytesmemory data) internalviewreturns (bytesmemory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/functionfunctionStaticCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalviewreturns (bytesmemory) {
(bool success, bytesmemory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target, bytesmemory data) internalreturns (bytesmemory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/functionfunctionDelegateCall(address target,
bytesmemory data,
stringmemory errorMessage
) internalreturns (bytesmemory) {
(bool success, bytesmemory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/functionverifyCallResultFromTarget(address target,
bool success,
bytesmemory returndata,
stringmemory errorMessage
) internalviewreturns (bytesmemory) {
if (success) {
if (returndata.length==0) {
// only check isContract if the call was successful and the return data is empty// otherwise we already know that it was a contractrequire(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/functionverifyCallResult(bool success,
bytesmemory returndata,
stringmemory errorMessage
) internalpurereturns (bytesmemory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function_revert(bytesmemory returndata, stringmemory errorMessage) privatepure{
// Look for revert reason and bubble it up if presentif (returndata.length>0) {
// The easiest way to bubble the revert reason is using memory via assembly/// @solidity memory-safe-assemblyassembly {
let returndata_size :=mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
Contract Source Code
File 2 of 21: BytesUtils.sol
//SPDX-License-Identifier: MITpragmasolidity ^0.8.4;libraryBytesUtils{
errorOffsetOutOfBoundsError(uint256 offset, uint256 length);
/*
* @dev Returns the keccak-256 hash of a byte range.
* @param self The byte string to hash.
* @param offset The position to start hashing at.
* @param len The number of bytes to hash.
* @return The hash of the byte range.
*/functionkeccak(bytesmemoryself,
uint256 offset,
uint256 len
) internalpurereturns (bytes32 ret) {
require(offset + len <=self.length);
assembly {
ret :=keccak256(add(add(self, 32), offset), len)
}
}
/**
* @dev Returns the ENS namehash of a DNS-encoded name.
* @param self The DNS-encoded name to hash.
* @param offset The offset at which to start hashing.
* @return The namehash of the name.
*/functionnamehash(bytesmemoryself,
uint256 offset
) internalpurereturns (bytes32) {
(bytes32 labelhash, uint256 newOffset) = readLabel(self, offset);
if (labelhash ==bytes32(0)) {
require(offset ==self.length-1, "namehash: Junk at end of name");
returnbytes32(0);
}
returnkeccak256(abi.encodePacked(namehash(self, newOffset), labelhash));
}
/**
* @dev Returns the keccak-256 hash of a DNS-encoded label, and the offset to the start of the next label.
* @param self The byte string to read a label from.
* @param idx The index to read a label at.
* @return labelhash The hash of the label at the specified index, or 0 if it is the last label.
* @return newIdx The index of the start of the next label.
*/functionreadLabel(bytesmemoryself,
uint256 idx
) internalpurereturns (bytes32 labelhash, uint256 newIdx) {
require(idx <self.length, "readLabel: Index out of bounds");
uint256 len =uint256(uint8(self[idx]));
if (len >0) {
labelhash = keccak(self, idx +1, len);
} else {
labelhash =bytes32(0);
}
newIdx = idx + len +1;
}
/*
* @dev Returns a positive number if `other` comes lexicographically after
* `self`, a negative number if it comes before, or zero if the
* contents of the two bytes are equal.
* @param self The first bytes to compare.
* @param other The second bytes to compare.
* @return The result of the comparison.
*/functioncompare(bytesmemoryself,
bytesmemory other
) internalpurereturns (int256) {
return compare(self, 0, self.length, other, 0, other.length);
}
/*
* @dev Returns a positive number if `other` comes lexicographically after
* `self`, a negative number if it comes before, or zero if the
* contents of the two bytes are equal. Comparison is done per-rune,
* on unicode codepoints.
* @param self The first bytes to compare.
* @param offset The offset of self.
* @param len The length of self.
* @param other The second bytes to compare.
* @param otheroffset The offset of the other string.
* @param otherlen The length of the other string.
* @return The result of the comparison.
*/functioncompare(bytesmemoryself,
uint256 offset,
uint256 len,
bytesmemory other,
uint256 otheroffset,
uint256 otherlen
) internalpurereturns (int256) {
if (offset + len >self.length) {
revert OffsetOutOfBoundsError(offset + len, self.length);
}
if (otheroffset + otherlen > other.length) {
revert OffsetOutOfBoundsError(otheroffset + otherlen, other.length);
}
uint256 shortest = len;
if (otherlen < len) shortest = otherlen;
uint256 selfptr;
uint256 otherptr;
assembly {
selfptr :=add(self, add(offset, 32))
otherptr :=add(other, add(otheroffset, 32))
}
for (uint256 idx =0; idx < shortest; idx +=32) {
uint256 a;
uint256 b;
assembly {
a :=mload(selfptr)
b :=mload(otherptr)
}
if (a != b) {
// Mask out irrelevant bytes and check againuint256 mask;
if (shortest - idx >=32) {
mask =type(uint256).max;
} else {
mask =~(2** (8* (idx +32- shortest)) -1);
}
int256 diff =int256(a & mask) -int256(b & mask);
if (diff !=0) return diff;
}
selfptr +=32;
otherptr +=32;
}
returnint256(len) -int256(otherlen);
}
/*
* @dev Returns true if the two byte ranges are equal.
* @param self The first byte range to compare.
* @param offset The offset into the first byte range.
* @param other The second byte range to compare.
* @param otherOffset The offset into the second byte range.
* @param len The number of bytes to compare
* @return True if the byte ranges are equal, false otherwise.
*/functionequals(bytesmemoryself,
uint256 offset,
bytesmemory other,
uint256 otherOffset,
uint256 len
) internalpurereturns (bool) {
return keccak(self, offset, len) == keccak(other, otherOffset, len);
}
/*
* @dev Returns true if the two byte ranges are equal with offsets.
* @param self The first byte range to compare.
* @param offset The offset into the first byte range.
* @param other The second byte range to compare.
* @param otherOffset The offset into the second byte range.
* @return True if the byte ranges are equal, false otherwise.
*/functionequals(bytesmemoryself,
uint256 offset,
bytesmemory other,
uint256 otherOffset
) internalpurereturns (bool) {
return
keccak(self, offset, self.length- offset) ==
keccak(other, otherOffset, other.length- otherOffset);
}
/*
* @dev Compares a range of 'self' to all of 'other' and returns True iff
* they are equal.
* @param self The first byte range to compare.
* @param offset The offset into the first byte range.
* @param other The second byte range to compare.
* @return True if the byte ranges are equal, false otherwise.
*/functionequals(bytesmemoryself,
uint256 offset,
bytesmemory other
) internalpurereturns (bool) {
returnself.length== offset + other.length&&
equals(self, offset, other, 0, other.length);
}
/*
* @dev Returns true if the two byte ranges are equal.
* @param self The first byte range to compare.
* @param other The second byte range to compare.
* @return True if the byte ranges are equal, false otherwise.
*/functionequals(bytesmemoryself,
bytesmemory other
) internalpurereturns (bool) {
returnself.length== other.length&&
equals(self, 0, other, 0, self.length);
}
/*
* @dev Returns the 8-bit number at the specified index of self.
* @param self The byte string.
* @param idx The index into the bytes
* @return The specified 8 bits of the string, interpreted as an integer.
*/functionreadUint8(bytesmemoryself,
uint256 idx
) internalpurereturns (uint8 ret) {
returnuint8(self[idx]);
}
/*
* @dev Returns the 16-bit number at the specified index of self.
* @param self The byte string.
* @param idx The index into the bytes
* @return The specified 16 bits of the string, interpreted as an integer.
*/functionreadUint16(bytesmemoryself,
uint256 idx
) internalpurereturns (uint16 ret) {
require(idx +2<=self.length);
assembly {
ret :=and(mload(add(add(self, 2), idx)), 0xFFFF)
}
}
/*
* @dev Returns the 32-bit number at the specified index of self.
* @param self The byte string.
* @param idx The index into the bytes
* @return The specified 32 bits of the string, interpreted as an integer.
*/functionreadUint32(bytesmemoryself,
uint256 idx
) internalpurereturns (uint32 ret) {
require(idx +4<=self.length);
assembly {
ret :=and(mload(add(add(self, 4), idx)), 0xFFFFFFFF)
}
}
/*
* @dev Returns the 32 byte value at the specified index of self.
* @param self The byte string.
* @param idx The index into the bytes
* @return The specified 32 bytes of the string.
*/functionreadBytes32(bytesmemoryself,
uint256 idx
) internalpurereturns (bytes32 ret) {
require(idx +32<=self.length);
assembly {
ret :=mload(add(add(self, 32), idx))
}
}
/*
* @dev Returns the 32 byte value at the specified index of self.
* @param self The byte string.
* @param idx The index into the bytes
* @return The specified 32 bytes of the string.
*/functionreadBytes20(bytesmemoryself,
uint256 idx
) internalpurereturns (bytes20 ret) {
require(idx +20<=self.length);
assembly {
ret :=and(
mload(add(add(self, 32), idx)),
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000
)
}
}
/*
* @dev Returns the n byte value at the specified index of self.
* @param self The byte string.
* @param idx The index into the bytes.
* @param len The number of bytes.
* @return The specified 32 bytes of the string.
*/functionreadBytesN(bytesmemoryself,
uint256 idx,
uint256 len
) internalpurereturns (bytes32 ret) {
require(len <=32);
require(idx + len <=self.length);
assembly {
let mask :=not(sub(exp(256, sub(32, len)), 1))
ret :=and(mload(add(add(self, 32), idx)), mask)
}
}
functionmemcpy(uint256 dest, uint256 src, uint256 len) privatepure{
// Copy word-length chunks while possiblefor (; len >=32; len -=32) {
assembly {
mstore(dest, mload(src))
}
dest +=32;
src +=32;
}
// Copy remaining bytesunchecked {
uint256 mask = (256** (32- len)) -1;
assembly {
let srcpart :=and(mload(src), not(mask))
let destpart :=and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
}
/*
* @dev Copies a substring into a new byte string.
* @param self The byte string to copy from.
* @param offset The offset to start copying at.
* @param len The number of bytes to copy.
*/functionsubstring(bytesmemoryself,
uint256 offset,
uint256 len
) internalpurereturns (bytesmemory) {
require(offset + len <=self.length);
bytesmemory ret =newbytes(len);
uint256 dest;
uint256 src;
assembly {
dest :=add(ret, 32)
src :=add(add(self, 32), offset)
}
memcpy(dest, src, len);
return ret;
}
// Maps characters from 0x30 to 0x7A to their base32 values.// 0xFF represents invalid characters in that range.bytesconstant base32HexTable =hex"00010203040506070809FFFFFFFFFFFFFF0A0B0C0D0E0F101112131415161718191A1B1C1D1E1FFFFFFFFFFFFFFFFFFFFF0A0B0C0D0E0F101112131415161718191A1B1C1D1E1F";
/**
* @dev Decodes unpadded base32 data of up to one word in length.
* @param self The data to decode.
* @param off Offset into the string to start at.
* @param len Number of characters to decode.
* @return The decoded data, left aligned.
*/functionbase32HexDecodeWord(bytesmemoryself,
uint256 off,
uint256 len
) internalpurereturns (bytes32) {
require(len <=52);
uint256 ret =0;
uint8 decoded;
for (uint256 i =0; i < len; i++) {
bytes1 char =self[off + i];
require(char >=0x30&& char <=0x7A);
decoded =uint8(base32HexTable[uint256(uint8(char)) -0x30]);
require(decoded <=0x20);
if (i == len -1) {
break;
}
ret = (ret <<5) | decoded;
}
uint256 bitlen = len *5;
if (len %8==0) {
// Multiple of 8 characters, no padding
ret = (ret <<5) | decoded;
} elseif (len %8==2) {
// Two extra characters - 1 byte
ret = (ret <<3) | (decoded >>2);
bitlen -=2;
} elseif (len %8==4) {
// Four extra characters - 2 bytes
ret = (ret <<1) | (decoded >>4);
bitlen -=4;
} elseif (len %8==5) {
// Five extra characters - 3 bytes
ret = (ret <<4) | (decoded >>1);
bitlen -=1;
} elseif (len %8==7) {
// Seven extra characters - 4 bytes
ret = (ret <<2) | (decoded >>3);
bitlen -=3;
} else {
revert();
}
returnbytes32(ret << (256- bitlen));
}
/**
* @dev Finds the first occurrence of the byte `needle` in `self`.
* @param self The string to search
* @param off The offset to start searching at
* @param len The number of bytes to search
* @param needle The byte to search for
* @return The offset of `needle` in `self`, or 2**256-1 if it was not found.
*/functionfind(bytesmemoryself,
uint256 off,
uint256 len,
bytes1 needle
) internalpurereturns (uint256) {
for (uint256 idx = off; idx < off + len; idx++) {
if (self[idx] == needle) {
return idx;
}
}
returntype(uint256).max;
}
}
Contract Source Code
File 3 of 21: ENS.sol
//SPDX-License-Identifier: MITpragmasolidity >=0.8.4;interfaceENS{
// Logged when the owner of a node assigns a new owner to a subnode.eventNewOwner(bytes32indexed node, bytes32indexed label, address owner);
// Logged when the owner of a node transfers ownership to a new account.eventTransfer(bytes32indexed node, address owner);
// Logged when the resolver for a node changes.eventNewResolver(bytes32indexed node, address resolver);
// Logged when the TTL of a node changeseventNewTTL(bytes32indexed node, uint64 ttl);
// Logged when an operator is added or removed.eventApprovalForAll(addressindexed owner,
addressindexed operator,
bool approved
);
functionsetRecord(bytes32 node,
address owner,
address resolver,
uint64 ttl
) external;
functionsetSubnodeRecord(bytes32 node,
bytes32 label,
address owner,
address resolver,
uint64 ttl
) external;
functionsetSubnodeOwner(bytes32 node,
bytes32 label,
address owner
) externalreturns (bytes32);
functionsetResolver(bytes32 node, address resolver) external;
functionsetOwner(bytes32 node, address owner) external;
functionsetTTL(bytes32 node, uint64 ttl) external;
functionsetApprovalForAll(address operator, bool approved) external;
functionowner(bytes32 node) externalviewreturns (address);
functionresolver(bytes32 node) externalviewreturns (address);
functionttl(bytes32 node) externalviewreturns (uint64);
functionrecordExists(bytes32 node) externalviewreturns (bool);
functionisApprovedForAll(address owner,
address operator
) externalviewreturns (bool);
}
Contract Source Code
File 4 of 21: ERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)pragmasolidity ^0.8.0;import"./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/abstractcontractERC165isIERC165{
/**
* @dev See {IERC165-supportsInterface}.
*/functionsupportsInterface(bytes4 interfaceId) publicviewvirtualoverridereturns (bool) {
return interfaceId ==type(IERC165).interfaceId;
}
}
Contract Source Code
File 5 of 21: EVMFetchTarget.sol
//SPDX-License-Identifier: MITpragmasolidity ^0.8.25;import {IEVMVerifier} from"./IEVMVerifier.sol";
import {Address} from"@openzeppelin/contracts/utils/Address.sol";
/**
* @dev Callback implementation for users of `EVMFetcher`. If you use `EVMFetcher`, your contract must
* inherit from this contract in order to handle callbacks correctly.
*/abstractcontractEVMFetchTarget{
usingAddressforaddress;
errorResponseLengthMismatch(uint256 actual, uint256 expected);
/**
* @dev Internal callback function invoked by CCIP-Read in response to a `getStorageSlots` request.
*/functiongetStorageSlotsCallback(bytescalldata response,
bytescalldata extradata
) externalreturns (bytesmemory) {
bytesmemory proof =abi.decode(response, (bytes));
(
IEVMVerifier verifier,
address addr,
bytes32[] memory commands,
bytes[] memory constants,
bytes4 callback,
bytesmemory callbackData
) =abi.decode(
extradata,
(IEVMVerifier, address, bytes32[], bytes[], bytes4, bytes)
);
bytes[] memory values = verifier.getStorageValues(
addr,
commands,
constants,
proof,
getAcceptedL2BlockRangeLength()
);
if (values.length!= commands.length) {
revert ResponseLengthMismatch(values.length, commands.length);
}
bytesmemory ret =address(this).functionCall(
abi.encodeWithSelector(callback, values, callbackData)
);
assembly {
return(add(ret, 32), mload(ret))
}
}
/**
* @dev The child contract has to return an accepted L2 block range used by the verifier
* to verify that the block number verified is in the accepted block range.
*/functiongetAcceptedL2BlockRangeLength()
publicviewvirtualreturns (uint256);
}
Contract Source Code
File 6 of 21: EVMFetcher.sol
//SPDX-License-Identifier: MITpragmasolidity ^0.8.25;import {IEVMVerifier} from"./IEVMVerifier.sol";
import {EVMFetchTarget} from"./EVMFetchTarget.sol";
import {Address} from"@openzeppelin/contracts/utils/Address.sol";
interfaceIEVMGateway{
functiongetStorageSlots(address addr,
bytes32[] memory commands,
bytes[] memory constants
) externalpurereturns (bytesmemory witness);
}
uint8constant FLAG_DYNAMIC =0x01;
uint8constant OP_CONSTANT =0x00;
uint8constant OP_BACKREF =0x20;
uint8constant OP_END =0xff;
/**
* @dev A library to facilitate requesting storage data proofs from contracts, possibly on a different chain.
* See l1-verifier/test/TestL1.sol for example usage.
*/libraryEVMFetcher{
uint256constant MAX_COMMANDS =32;
uint256constant MAX_CONSTANTS =32; // Must not be greater than 32usingAddressforaddress;
errorTooManyCommands(uint256 max);
errorCommandTooLong();
errorInvalidReference(uint256 value, uint256 max);
errorOffchainLookup(address sender,
string[] urls,
bytes callData,
bytes4 callbackFunction,
bytes extraData
);
structEVMFetchRequest {
IEVMVerifier verifier;
address target;
bytes32[] commands;
uint256 operationIdx;
bytes[] constants;
}
/**
* @dev Creates a request to fetch the value of multiple storage slots from a contract via CCIP-Read, possibly from
* another chain.
* Supports dynamic length values and slot numbers derived from other retrieved values.
* @param verifier An instance of a verifier contract that can provide and verify the storage slot information.
* @param target The address of the contract to fetch storage proofs for.
*/functionnewFetchRequest(
IEVMVerifier verifier,
address target
) internalpurereturns (EVMFetchRequest memory) {
bytes32[] memory commands =newbytes32[](MAX_COMMANDS);
bytes[] memory constants =newbytes[](MAX_CONSTANTS);
assembly {
mstore(commands, 0) // Set current array length to 0mstore(constants, 0)
}
return EVMFetchRequest(verifier, target, commands, 0, constants);
}
/**
* @dev Starts describing a new fetch request.
* Paths specify a series of hashing operations to derive the final slot ID.
* See https://docs.soliditylang.org/en/v0.8.17/internals/layout_in_storage.html for details on how Solidity
* lays out storage variables.
* @param request The request object being operated on.
* @param baseSlot The base slot ID that forms the root of the path.
*/functiongetStatic(
EVMFetchRequest memory request,
uint256 baseSlot
) internalpurereturns (EVMFetchRequest memory) {
bytes32[] memory commands = request.commands;
uint256 commandIdx = commands.length;
if (commandIdx >0&& request.operationIdx <32) {
// Terminate previous command
_addOperation(request, OP_END);
}
assembly {
mstore(commands, add(commandIdx, 1)) // Increment command array length
}
if (request.commands.length> MAX_COMMANDS) {
revert TooManyCommands(MAX_COMMANDS);
}
request.operationIdx =0;
_addOperation(request, 0);
_addOperation(request, _addConstant(request, abi.encode(baseSlot)));
return request;
}
/**
* @dev Starts describing a new fetch request.
* Paths specify a series of hashing operations to derive the final slot ID.
* See https://docs.soliditylang.org/en/v0.8.17/internals/layout_in_storage.html for details on how Solidity
* lays out storage variables.
* @param request The request object being operated on.
* @param baseSlot The base slot ID that forms the root of the path.
*/functiongetDynamic(
EVMFetchRequest memory request,
uint256 baseSlot
) internalpurereturns (EVMFetchRequest memory) {
bytes32[] memory commands = request.commands;
uint256 commandIdx = commands.length;
if (commandIdx >0&& request.operationIdx <32) {
// Terminate previous command
_addOperation(request, OP_END);
}
assembly {
mstore(commands, add(commandIdx, 1)) // Increment command array length
}
if (request.commands.length> MAX_COMMANDS) {
revert TooManyCommands(MAX_COMMANDS);
}
request.operationIdx =0;
_addOperation(request, FLAG_DYNAMIC);
_addOperation(request, _addConstant(request, abi.encode(baseSlot)));
return request;
}
/**
* @dev Adds a `uint256` element to the current path.
* @param request The request object being operated on.
* @param el The element to add.
*/functionelement(
EVMFetchRequest memory request,
uint256 el
) internalpurereturns (EVMFetchRequest memory) {
if (request.operationIdx >=32) {
revert CommandTooLong();
}
_addOperation(request, _addConstant(request, abi.encode(el)));
return request;
}
/**
* @dev Adds a `bytes32` element to the current path.
* @param request The request object being operated on.
* @param el The element to add.
*/functionelement(
EVMFetchRequest memory request,
bytes32 el
) internalpurereturns (EVMFetchRequest memory) {
if (request.operationIdx >=32) {
revert CommandTooLong();
}
_addOperation(request, _addConstant(request, abi.encode(el)));
return request;
}
/**
* @dev Adds an `address` element to the current path.
* @param request The request object being operated on.
* @param el The element to add.
*/functionelement(
EVMFetchRequest memory request,
address el
) internalpurereturns (EVMFetchRequest memory) {
if (request.operationIdx >=32) {
revert CommandTooLong();
}
_addOperation(request, _addConstant(request, abi.encode(el)));
return request;
}
/**
* @dev Adds a `bytes` element to the current path.
* @param request The request object being operated on.
* @param el The element to add.
*/functionelement(
EVMFetchRequest memory request,
bytesmemory el
) internalpurereturns (EVMFetchRequest memory) {
if (request.operationIdx >=32) {
revert CommandTooLong();
}
_addOperation(request, _addConstant(request, el));
return request;
}
/**
* @dev Adds a `string` element to the current path.
* @param request The request object being operated on.
* @param el The element to add.
*/functionelement(
EVMFetchRequest memory request,
stringmemory el
) internalpurereturns (EVMFetchRequest memory) {
if (request.operationIdx >=32) {
revert CommandTooLong();
}
_addOperation(request, _addConstant(request, bytes(el)));
return request;
}
/**
* @dev Adds a reference to a previous fetch to the current path.
* @param request The request object being operated on.
* @param idx The index of the previous fetch request, starting at 0.
*/functionref(
EVMFetchRequest memory request,
uint8 idx
) internalpurereturns (EVMFetchRequest memory) {
if (request.operationIdx >=32) {
revert CommandTooLong();
}
if (idx > request.commands.length|| idx >31) {
revert InvalidReference(idx, request.commands.length);
}
_addOperation(request, OP_BACKREF | idx);
return request;
}
/**
* @dev Initiates the fetch request.
* Calling this function terminates execution; clients that implement CCIP-Read will make a callback to
* `callback` with the results of the operation.
* @param callbackId A callback function selector on this contract that will be invoked via CCIP-Read with the result of the lookup.
* The function must have a signature matching `(bytes[] memory values, bytes callbackData)` with a return type matching the call in which
* this function was invoked. Its return data will be returned as the return value of the entire CCIP-read operation.
* @param callbackData Extra data to supply to the callback.
*/functionfetch(
EVMFetchRequest memory request,
bytes4 callbackId,
bytesmemory callbackData
) internalview{
if (request.commands.length>0&& request.operationIdx <32) {
// Terminate last command
_addOperation(request, OP_END);
}
revert OffchainLookup(
address(this),
request.verifier.gatewayURLs(),
abi.encodeCall(
IEVMGateway.getStorageSlots,
(request.target, request.commands, request.constants)
),
EVMFetchTarget.getStorageSlotsCallback.selector,
abi.encode(
request.verifier,
request.target,
request.commands,
request.constants,
callbackId,
callbackData
)
);
}
function_addConstant(
EVMFetchRequest memory request,
bytesmemory value
) privatepurereturns (uint8 idx) {
bytes[] memory constants = request.constants;
idx =uint8(constants.length);
assembly {
mstore(constants, add(idx, 1)) // Increment constant array length
}
constants[idx] = value;
}
function_addOperation(
EVMFetchRequest memory request,
uint8 op
) privatepure{
uint256 commandIdx = request.commands.length-1;
request.commands[commandIdx] =
request.commands[commandIdx] |
(bytes32(bytes1(op)) >> (8* request.operationIdx++));
}
}
Contract Source Code
File 7 of 21: IAddrResolver.sol
// SPDX-License-Identifier: MITpragmasolidity >=0.8.4;/**
* Interface for the legacy (ETH-only) addr function.
*/interfaceIAddrResolver{
eventAddrChanged(bytes32indexed node, address a);
/**
* Returns the address associated with an ENS node.
* @param node The ENS node to query.
* @return The associated address.
*/functionaddr(bytes32 node) externalviewreturns (addresspayable);
}
// SPDX-License-Identifier: MITpragmasolidity >=0.8.4;/**
* Interface for the new (multicoin) addr function.
*/interfaceIAddressResolver{
eventAddressChanged(bytes32indexed node,
uint256 coinType,
bytes newAddress
);
functionaddr(bytes32 node,
uint256 coinType
) externalviewreturns (bytesmemory);
}
Contract Source Code
File 10 of 21: IBaseRegistrar.sol
import"../registry/ENS.sol";
import"./IBaseRegistrar.sol";
import"@openzeppelin/contracts/token/ERC721/IERC721.sol";
interfaceIBaseRegistrarisIERC721{
eventControllerAdded(addressindexed controller);
eventControllerRemoved(addressindexed controller);
eventNameMigrated(uint256indexed id,
addressindexed owner,
uint256 expires
);
eventNameRegistered(uint256indexed id,
addressindexed owner,
uint256 expires
);
eventNameRenewed(uint256indexed id, uint256 expires);
// Authorises a controller, who can register and renew domains.functionaddController(address controller) external;
// Revoke controller permission for an address.functionremoveController(address controller) external;
// Set the resolver for the TLD this registrar manages.functionsetResolver(address resolver) external;
// Returns the expiration timestamp of the specified label hash.functionnameExpires(uint256 id) externalviewreturns (uint256);
// Returns true if the specified name is available for registration.functionavailable(uint256 id) externalviewreturns (bool);
/**
* @dev Register a name.
*/functionregister(uint256 id,
address owner,
uint256 duration
) externalreturns (uint256);
functionrenew(uint256 id, uint256 duration) externalreturns (uint256);
/**
* @dev Reclaim ownership of a name in ENS, if you own it in the registrar.
*/functionreclaim(uint256 id, address owner) external;
}
Contract Source Code
File 11 of 21: IERC1155.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/IERC1155.sol)pragmasolidity ^0.8.0;import"../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
*/interfaceIERC1155isIERC165{
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/eventTransferSingle(addressindexed operator, addressindexedfrom, addressindexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/eventTransferBatch(addressindexed operator,
addressindexedfrom,
addressindexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/eventApprovalForAll(addressindexed account, addressindexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/eventURI(string value, uint256indexed id);
/**
* @dev Returns the amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/functionbalanceOf(address account, uint256 id) externalviewreturns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/functionbalanceOfBatch(address[] calldata accounts,
uint256[] calldata ids
) externalviewreturns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/functionsetApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/functionisApprovedForAll(address account, address operator) externalviewreturns (bool);
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/functionsafeTransferFrom(addressfrom, address to, uint256 id, uint256 amount, bytescalldata data) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/functionsafeBatchTransferFrom(addressfrom,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytescalldata data
) external;
}
Contract Source Code
File 12 of 21: IERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)pragmasolidity ^0.8.0;/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/interfaceIERC165{
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/functionsupportsInterface(bytes4 interfaceId) externalviewreturns (bool);
}
Contract Source Code
File 13 of 21: IERC721.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)pragmasolidity ^0.8.0;import"../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/interfaceIERC721isIERC165{
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/eventTransfer(addressindexedfrom, addressindexed to, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/eventApproval(addressindexed owner, addressindexed approved, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/eventApprovalForAll(addressindexed owner, addressindexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/functionbalanceOf(address owner) externalviewreturns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functionownerOf(uint256 tokenId) externalviewreturns (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.
*/functionsafeTransferFrom(addressfrom, address to, uint256 tokenId, bytescalldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 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.
*/functionsafeTransferFrom(addressfrom, 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 ERC721
* 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.
*/functiontransferFrom(addressfrom, 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.
*/functionapprove(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 caller.
*
* Emits an {ApprovalForAll} event.
*/functionsetApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functiongetApproved(uint256 tokenId) externalviewreturns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/functionisApprovedForAll(address owner, address operator) externalviewreturns (bool);
}
// SPDX-License-Identifier: Apache-2.0pragmasolidity 0.8.25;/**
* @title Library to perform ENS label manipulation
* @author ConsenSys Software Inc.
*/libraryLabelUtils{
/**
* Extract the first label name from a dns encoded ens domain
* @param name the dns encoded ENS domain
* @return label as bytes
*/functionextractFirstLabel(bytesmemory name
) externalpurereturns (bytesmemory) {
uint256 idx =0;
uint8 labelLength =uint8(name[idx]);
idx++;
bytesmemory label =newbytes(labelLength);
for (uint256 i =0; i < labelLength; i++) {
label[i] = name[idx + i];
}
return label;
}
/**
* Extract the numeric suffix from the dns encoded label
* @param label the dns encoded label
* @return number the numeric suffix
*/functionextractNumericSuffix(bytesmemory label
) externalpurereturns (uint256) {
uint256 num =0;
bool hasNumber =false;
for (uint256 i =0; i < label.length; i++) {
uint8 char =uint8(label[i]);
if (char >=48&& char <=57) {
// ASCII for '0' is 48 and '9' is 57
num = num *10+ (char -48);
hasNumber =true;
} elseif (hasNumber) {
// Break on first non-digit after starting to read numbersbreak;
}
}
require(hasNumber, "No numeric suffix found");
return num;
}
/**
* Check if the bytes param is a number or not
* @param input bytes to check
* @return true if number, false otherwise
*/functionisNumber(bytesmemory input) publicpurereturns (bool) {
for (uint i =0; i < input.length; i++) {
// Check if each byte is within the ASCII range for '0' to '9'if (input[i] <0x30|| input[i] >0x39) {
returnfalse;
}
}
returntrue;
}
/**
* Counts the number of labels in the DNS encoded input given
* @param input the DNS encoded input to count from
* @return number labels found
*/functioncountLabels(bytesmemory input) publicpurereturns (uint) {
uint count =0;
uint i =0;
while (i < input.length) {
uint labelLength =uint(uint8(input[i]));
if (labelLength ==0) {
break; // End of the DNS name
}
count++;
i += labelLength +1;
}
return count;
}
}
Contract Source Code
File 21 of 21: NFTResolver.sol
// SPDX-License-Identifier: Apache-2.0pragmasolidity 0.8.25;import {EVMFetcher} from"@consensys/linea-state-verifier/contracts/EVMFetcher.sol";
import {EVMFetchTarget} from"@consensys/linea-state-verifier/contracts/EVMFetchTarget.sol";
import {IEVMVerifier} from"@consensys/linea-state-verifier/contracts/IEVMVerifier.sol";
import"@ensdomains/ens-contracts/contracts/registry/ENS.sol";
import {INameWrapper} from"@ensdomains/ens-contracts/contracts/wrapper/INameWrapper.sol";
import {BytesUtils} from"@ensdomains/ens-contracts/contracts/utils/BytesUtils.sol";
import {IAddrResolver} from"@ensdomains/ens-contracts/contracts/resolvers/profiles/IAddrResolver.sol";
import {IAddressResolver} from"@ensdomains/ens-contracts/contracts/resolvers/profiles/IAddressResolver.sol";
import"@ensdomains/ens-contracts/contracts/resolvers/profiles/IExtendedResolver.sol";
import {ITargetResolver} from"./ITargetResolver.sol";
import {IAddrSetter} from"./IAddrSetter.sol";
import"@openzeppelin/contracts/utils/introspection/ERC165.sol";
import {LabelUtils} from"./LabelUtils.sol";
contractNFTResolverisEVMFetchTarget,
ITargetResolver,
IExtendedResolver,
IAddrSetter,
ERC165{
usingEVMFetcherforEVMFetcher.EVMFetchRequest;
usingBytesUtilsforbytes;
IEVMVerifier publicimmutable verifier;
ENS publicimmutable ens;
INameWrapper publicimmutable nameWrapper;
uint256publicimmutable l2ChainId;
// PublicResolver used to resolve a base domain such as xxx.eth when queriedaddresspublicimmutable publicResolver;
mapping(bytes32=>address) targets;
uint256constant OWNERS_SLOT =2;
// To check how old is the value/proof returned and is in the acceptable rangeuint256constant ACCEPTED_L2_BLOCK_RANGE_LENGTH =86400;
eventTargetSet(bytes name, address target);
functionisAuthorised(bytes32 node) internalviewreturns (bool) {
address owner = ens.owner(node);
if (owner ==address(nameWrapper)) {
owner = nameWrapper.ownerOf(uint256(node));
}
return owner ==msg.sender;
}
/**
* @dev EIP-5559 - Error to raise when mutations are being deferred to an L2.
* @param chainId Chain ID to perform the deferred mutation to.
* @param contractAddress Contract Address at which the deferred mutation should transact with.
*/errorStorageHandledByL2(uint256 chainId, address contractAddress);
/**
* @param _verifier The chain verifier address
* @param _ens The ENS registry address
* @param _nameWrapper The ENS name wrapper address
* @param _l2ChainId The chainId at which the resolver resolves data from
* @param _publicResolver The PublicResolver address to use to resolve base domains
*/constructor(
IEVMVerifier _verifier,
ENS _ens,
INameWrapper _nameWrapper,
uint256 _l2ChainId,
address _publicResolver
) {
require(
address(_nameWrapper) !=address(0),
"Name Wrapper address must be set"
);
require(
address(_verifier) !=address(0),
"Verifier address must be set"
);
require(address(_ens) !=address(0), "Registry address must be set");
verifier = _verifier;
ens = _ens;
nameWrapper = _nameWrapper;
l2ChainId = _l2ChainId;
publicResolver = _publicResolver;
}
/**
* @dev inherits from EVMFetchTarget
*/functiongetAcceptedL2BlockRangeLength()
publicpureoverridereturns (uint256)
{
return ACCEPTED_L2_BLOCK_RANGE_LENGTH;
}
/**
* Set target address to verify against
* @param name The encoded name to query.
* @param target The L2 resolver address to verify against.
*/functionsetTarget(bytescalldata name, address target) external{
(bytes32 node, ) = getTarget(name);
require(
isAuthorised(node),
"Not authorized to set target for this node"
);
targets[node] = target;
emit TargetSet(name, target);
}
/**
* @dev Returns the L2 target address that can answer queries for `name`.
* @param name DNS encoded ENS name to query
* @return node The node of the name
* @return target The L2 resolver address to verify against.
*/functiongetTarget(bytesmemory name
) publicviewreturns (bytes32 node, address target) {
return _getTarget(name, 0);
}
function_getTarget(bytesmemory name,
uint256 offset
) privateviewreturns (bytes32 node, address target) {
uint256 len = name.readUint8(offset);
node =bytes32(0);
if (len >0) {
bytes32 label = name.keccak(offset +1, len);
(node, target) = _getTarget(name, offset + len +1);
node =keccak256(abi.encodePacked(node, label));
if (targets[node] !=address(0)) {
return (node, targets[node]);
}
} else {
return (bytes32(0), address(0));
}
return (node, target);
}
/**
* @dev Resolve and verify a record stored in l2 target address. It supports subname by fetching target recursively to the nearest parent.
* @param name DNS encoded ENS name to query
* @param data The actual calldata
* @return result result of the call
*/functionresolve(bytescalldata name,
bytescalldata data
) externalviewreturns (bytesmemory result) {
require(data.length>=4, "param data too short");
bytes32 node =abi.decode(data[4:], (bytes32));
bool isBaseDomain = targets[node] !=address(0);
// If trying to resolve the base domain, we use the PublicResolverif (isBaseDomain) {
return _resolve(name, data);
}
// Only accept 1 level subdomainrequire(LabelUtils.countLabels(name) <=3, "Too many subdomain levels");
(, address target) = _getTarget(name, 0);
bytes4 selector =bytes4(data);
if (selector == IAddrResolver.addr.selector) {
// Get NFT Index from theuint256 nftId = extractNFTId(name);
return _addr(nftId, target);
}
// None selector has been found it revertsrevert("invalid selector");
}
/**
* Get the NFT Id from the ENS name's label
* @param name DNS encoded ENS name
* @return id the NFT id
*/functionextractNFTId(bytescalldata name) publicpurereturns (uint256) {
bytesmemory firstLabel = LabelUtils.extractFirstLabel(name);
// Only accept numbers as the labelrequire(LabelUtils.isNumber(firstLabel), "Label is not a number");
return LabelUtils.extractNumericSuffix(firstLabel);
}
/**
* @dev Resolve and throws an EIP 3559 compliant error
* @param name DNS encoded ENS name to query
* @param _addr The actual calldata
* @return result result of the call
*/functionsetAddr(bytescalldata name,
address _addr
) externalviewreturns (bytesmemory result) {
(, address target) = _getTarget(name, 0);
_writeDeferral(target);
}
/**
* @dev The `PublicResolver` does not implement the `resolve(bytes,bytes)` method.
* This method completes the resolution request by staticcalling `PublicResolver` with the resolve request.
* Implementation matches the ENS `ExtendedResolver:resolve(bytes,bytes)` method with the exception that it `staticcall`s the
* the `rootResolver` instead of `address(this)`.
* @param data The ABI encoded data for the underlying resolution function (Eg, addr(bytes32), text(bytes32,string), etc).
* @return The return data, ABI encoded identically to the underlying function.
*/function_resolve(bytesmemory,
bytesmemory data
) internalviewreturns (bytesmemory) {
(bool success, bytesmemory result) = publicResolver.staticcall(data);
if (success) {
return result;
} else {
// Revert with the reason provided by the callassembly {
revert(add(result, 0x20), mload(result))
}
}
}
function_addr(uint256 tokenId,
address target
) privateviewreturns (bytesmemory) {
EVMFetcher
.newFetchRequest(verifier, target)
.getStatic(OWNERS_SLOT)
.element(tokenId)
.fetch(this.addrCallback.selector, ""); // recordVersions
}
functionaddrCallback(bytes[] memory values,
bytesmemory) externalpurereturns (bytesmemory) {
address addr =abi.decode(values[0], (address));
returnabi.encode(addr);
}
functionsupportsInterface(bytes4 interfaceId
) publicviewoverridereturns (bool) {
return
interfaceId ==type(IExtendedResolver).interfaceId||
interfaceId ==type(ITargetResolver).interfaceId||
interfaceId ==type(IAddrSetter).interfaceId||super.supportsInterface(interfaceId);
}
function_writeDeferral(address target) internalview{
revert StorageHandledByL2(l2ChainId, target);
}
}