Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 17417926 | 15 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
PublicResolver
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
import "../registry/ENS.sol";
import "./profiles/ABIResolver.sol";
import "./profiles/AddrResolver.sol";
import "./profiles/ContentHashResolver.sol";
import "./profiles/DNSResolver.sol";
import "./profiles/InterfaceResolver.sol";
import "./profiles/NameResolver.sol";
import "./profiles/PubkeyResolver.sol";
import "./profiles/TextResolver.sol";
import "./Multicallable.sol";
interface INameWrapper {
function ownerOf(uint256 id) external view returns (address);
}
/**
* A simple resolver anyone can use; only allows the owner of a node to set its
* address.
*/
contract PublicResolver is Multicallable, ABIResolver, AddrResolver, ContentHashResolver, DNSResolver, InterfaceResolver, NameResolver, PubkeyResolver, TextResolver {
ENS ens;
INameWrapper nameWrapper;
/**
* A mapping of operators. An address that is authorised for an address
* may make any changes to the name that the owner could, but may not update
* the set of authorisations.
* (owner, operator) => approved
*/
mapping(address => mapping(address => bool)) private _operatorApprovals;
// Logged when an operator is added or removed.
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
constructor(ENS _ens, INameWrapper wrapperAddress){
ens = _ens;
nameWrapper = wrapperAddress;
}
/**
* @dev See {IERC1155-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) external{
require(
msg.sender != operator,
"ERC1155: setting approval status for self"
);
_operatorApprovals[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
function isAuthorised(bytes32 node) internal override view returns(bool) {
address owner = ens.owner(node);
if(owner == address(nameWrapper) ){
owner = nameWrapper.ownerOf(uint256(node));
}
return owner == msg.sender || isApprovedForAll(owner, msg.sender);
}
/**
* @dev See {IERC1155-isApprovedForAll}.
*/
function isApprovedForAll(address account, address operator) public view returns (bool){
return _operatorApprovals[account][operator];
}
function supportsInterface(bytes4 interfaceID) public override(Multicallable, ABIResolver, AddrResolver, ContentHashResolver, DNSResolver, InterfaceResolver, NameResolver, PubkeyResolver, TextResolver) pure returns(bool) {
return interfaceID == type(IMulticallable).interfaceId || super.supportsInterface(interfaceID);
}
}pragma solidity >=0.8.4;
interface ENS {
// Logged when the owner of a node assigns a new owner to a subnode.
event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
// Logged when the owner of a node transfers ownership to a new account.
event Transfer(bytes32 indexed node, address owner);
// Logged when the resolver for a node changes.
event NewResolver(bytes32 indexed node, address resolver);
// Logged when the TTL of a node changes
event NewTTL(bytes32 indexed node, uint64 ttl);
// Logged when an operator is added or removed.
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function setRecord(bytes32 node, address owner, address resolver, uint64 ttl) external virtual;
function setSubnodeRecord(bytes32 node, bytes32 label, address owner, address resolver, uint64 ttl) external virtual;
function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external virtual returns(bytes32);
function setResolver(bytes32 node, address resolver) external virtual;
function setOwner(bytes32 node, address owner) external virtual;
function setTTL(bytes32 node, uint64 ttl) external virtual;
function setApprovalForAll(address operator, bool approved) external virtual;
function owner(bytes32 node) external virtual view returns (address);
function resolver(bytes32 node) external virtual view returns (address);
function ttl(bytes32 node) external virtual view returns (uint64);
function recordExists(bytes32 node) external virtual view returns (bool);
function isApprovedForAll(address owner, address operator) external virtual view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
import "./IABIResolver.sol";
import "../ResolverBase.sol";
abstract contract ABIResolver is IABIResolver, ResolverBase {
mapping(bytes32=>mapping(uint256=>bytes)) abis;
/**
* Sets the ABI associated with an ENS node.
* Nodes may have one ABI of each content type. To remove an ABI, set it to
* the empty string.
* @param node The node to update.
* @param contentType The content type of the ABI
* @param data The ABI data.
*/
function setABI(bytes32 node, uint256 contentType, bytes calldata data) virtual external authorised(node) {
// Content types must be powers of 2
require(((contentType - 1) & contentType) == 0);
abis[node][contentType] = data;
emit ABIChanged(node, contentType);
}
/**
* Returns the ABI associated with an ENS node.
* Defined in EIP205.
* @param node The ENS node to query
* @param contentTypes A bitwise OR of the ABI formats accepted by the caller.
* @return contentType The content type of the return value
* @return data The ABI data
*/
function ABI(bytes32 node, uint256 contentTypes) virtual override external view returns (uint256, bytes memory) {
mapping(uint256=>bytes) storage abiset = abis[node];
for (uint256 contentType = 1; contentType <= contentTypes; contentType <<= 1) {
if ((contentType & contentTypes) != 0 && abiset[contentType].length > 0) {
return (contentType, abiset[contentType]);
}
}
return (0, bytes(""));
}
function supportsInterface(bytes4 interfaceID) virtual override public pure returns(bool) {
return interfaceID == type(IABIResolver).interfaceId || super.supportsInterface(interfaceID);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
import "../ResolverBase.sol";
import "./IAddrResolver.sol";
import "./IAddressResolver.sol";
abstract contract AddrResolver is IAddrResolver, IAddressResolver, ResolverBase {
uint constant private COIN_TYPE_ETH = 60;
mapping(bytes32=>mapping(uint=>bytes)) _addresses;
/**
* Sets the address associated with an ENS node.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @param a The address to set.
*/
function setAddr(bytes32 node, address a) virtual external authorised(node) {
setAddr(node, COIN_TYPE_ETH, addressToBytes(a));
}
/**
* Returns the address associated with an ENS node.
* @param node The ENS node to query.
* @return The associated address.
*/
function addr(bytes32 node) virtual override public view returns (address payable) {
bytes memory a = addr(node, COIN_TYPE_ETH);
if(a.length == 0) {
return payable(0);
}
return bytesToAddress(a);
}
function setAddr(bytes32 node, uint coinType, bytes memory a) virtual public authorised(node) {
emit AddressChanged(node, coinType, a);
if(coinType == COIN_TYPE_ETH) {
emit AddrChanged(node, bytesToAddress(a));
}
_addresses[node][coinType] = a;
}
function addr(bytes32 node, uint coinType) virtual override public view returns(bytes memory) {
return _addresses[node][coinType];
}
function supportsInterface(bytes4 interfaceID) virtual override public pure returns(bool) {
return interfaceID == type(IAddrResolver).interfaceId || interfaceID == type(IAddressResolver).interfaceId || super.supportsInterface(interfaceID);
}
function bytesToAddress(bytes memory b) internal pure returns(address payable a) {
require(b.length == 20);
assembly {
a := div(mload(add(b, 32)), exp(256, 12))
}
}
function addressToBytes(address a) internal pure returns(bytes memory b) {
b = new bytes(20);
assembly {
mstore(add(b, 32), mul(a, exp(256, 12)))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
import "../ResolverBase.sol";
import "./IContentHashResolver.sol";
abstract contract ContentHashResolver is IContentHashResolver, ResolverBase {
mapping(bytes32=>bytes) hashes;
/**
* Sets the contenthash associated with an ENS node.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @param hash The contenthash to set
*/
function setContenthash(bytes32 node, bytes calldata hash) virtual external authorised(node) {
hashes[node] = hash;
emit ContenthashChanged(node, hash);
}
/**
* Returns the contenthash associated with an ENS node.
* @param node The ENS node to query.
* @return The associated contenthash.
*/
function contenthash(bytes32 node) virtual external override view returns (bytes memory) {
return hashes[node];
}
function supportsInterface(bytes4 interfaceID) virtual override public pure returns(bool) {
return interfaceID == type(IContentHashResolver).interfaceId || super.supportsInterface(interfaceID);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
import "../ResolverBase.sol";
import "../../dnssec-oracle/RRUtils.sol";
import "./IDNSRecordResolver.sol";
import "./IDNSZoneResolver.sol";
abstract contract DNSResolver is IDNSRecordResolver, IDNSZoneResolver, ResolverBase {
using RRUtils for *;
using BytesUtils for bytes;
// Zone hashes for the domains.
// A zone hash is an EIP-1577 content hash in binary format that should point to a
// resource containing a single zonefile.
// node => contenthash
mapping(bytes32=>bytes) private zonehashes;
// Version the mapping for each zone. This allows users who have lost
// track of their entries to effectively delete an entire zone by bumping
// the version number.
// node => version
mapping(bytes32=>uint256) private versions;
// The records themselves. Stored as binary RRSETs
// node => version => name => resource => data
mapping(bytes32=>mapping(uint256=>mapping(bytes32=>mapping(uint16=>bytes)))) private records;
// Count of number of entries for a given name. Required for DNS resolvers
// when resolving wildcards.
// node => version => name => number of records
mapping(bytes32=>mapping(uint256=>mapping(bytes32=>uint16))) private nameEntriesCount;
/**
* Set one or more DNS records. Records are supplied in wire-format.
* Records with the same node/name/resource must be supplied one after the
* other to ensure the data is updated correctly. For example, if the data
* was supplied:
* a.example.com IN A 1.2.3.4
* a.example.com IN A 5.6.7.8
* www.example.com IN CNAME a.example.com.
* then this would store the two A records for a.example.com correctly as a
* single RRSET, however if the data was supplied:
* a.example.com IN A 1.2.3.4
* www.example.com IN CNAME a.example.com.
* a.example.com IN A 5.6.7.8
* then this would store the first A record, the CNAME, then the second A
* record which would overwrite the first.
*
* @param node the namehash of the node for which to set the records
* @param data the DNS wire format records to set
*/
function setDNSRecords(bytes32 node, bytes calldata data) virtual external authorised(node) {
uint16 resource = 0;
uint256 offset = 0;
bytes memory name;
bytes memory value;
bytes32 nameHash;
// Iterate over the data to add the resource records
for (RRUtils.RRIterator memory iter = data.iterateRRs(0); !iter.done(); iter.next()) {
if (resource == 0) {
resource = iter.dnstype;
name = iter.name();
nameHash = keccak256(abi.encodePacked(name));
value = bytes(iter.rdata());
} else {
bytes memory newName = iter.name();
if (resource != iter.dnstype || !name.equals(newName)) {
setDNSRRSet(node, name, resource, data, offset, iter.offset - offset, value.length == 0);
resource = iter.dnstype;
offset = iter.offset;
name = newName;
nameHash = keccak256(name);
value = bytes(iter.rdata());
}
}
}
if (name.length > 0) {
setDNSRRSet(node, name, resource, data, offset, data.length - offset, value.length == 0);
}
}
/**
* Obtain a DNS record.
* @param node the namehash of the node for which to fetch the record
* @param name the keccak-256 hash of the fully-qualified name for which to fetch the record
* @param resource the ID of the resource as per https://en.wikipedia.org/wiki/List_of_DNS_record_types
* @return the DNS record in wire format if present, otherwise empty
*/
function dnsRecord(bytes32 node, bytes32 name, uint16 resource) virtual override public view returns (bytes memory) {
return records[node][versions[node]][name][resource];
}
/**
* Check if a given node has records.
* @param node the namehash of the node for which to check the records
* @param name the namehash of the node for which to check the records
*/
function hasDNSRecords(bytes32 node, bytes32 name) virtual public view returns (bool) {
return (nameEntriesCount[node][versions[node]][name] != 0);
}
/**
* Clear all information for a DNS zone.
* @param node the namehash of the node for which to clear the zone
*/
function clearDNSZone(bytes32 node) virtual public authorised(node) {
versions[node]++;
emit DNSZoneCleared(node);
}
/**
* setZonehash sets the hash for the zone.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @param hash The zonehash to set
*/
function setZonehash(bytes32 node, bytes calldata hash) virtual external authorised(node) {
bytes memory oldhash = zonehashes[node];
zonehashes[node] = hash;
emit DNSZonehashChanged(node, oldhash, hash);
}
/**
* zonehash obtains the hash for the zone.
* @param node The ENS node to query.
* @return The associated contenthash.
*/
function zonehash(bytes32 node) virtual override external view returns (bytes memory) {
return zonehashes[node];
}
function supportsInterface(bytes4 interfaceID) virtual override public pure returns(bool) {
return interfaceID == type(IDNSRecordResolver).interfaceId ||
interfaceID == type(IDNSZoneResolver).interfaceId ||
super.supportsInterface(interfaceID);
}
function setDNSRRSet(
bytes32 node,
bytes memory name,
uint16 resource,
bytes memory data,
uint256 offset,
uint256 size,
bool deleteRecord) private
{
uint256 version = versions[node];
bytes32 nameHash = keccak256(name);
bytes memory rrData = data.substring(offset, size);
if (deleteRecord) {
if (records[node][version][nameHash][resource].length != 0) {
nameEntriesCount[node][version][nameHash]--;
}
delete(records[node][version][nameHash][resource]);
emit DNSRecordDeleted(node, name, resource);
} else {
if (records[node][version][nameHash][resource].length == 0) {
nameEntriesCount[node][version][nameHash]++;
}
records[node][version][nameHash][resource] = rrData;
emit DNSRecordChanged(node, name, resource, rrData);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
import "../ResolverBase.sol";
import "../ISupportsInterface.sol";
import "./AddrResolver.sol";
import "./IInterfaceResolver.sol";
abstract contract InterfaceResolver is IInterfaceResolver, AddrResolver {
mapping(bytes32=>mapping(bytes4=>address)) interfaces;
/**
* Sets an interface associated with a name.
* Setting the address to 0 restores the default behaviour of querying the contract at `addr()` for interface support.
* @param node The node to update.
* @param interfaceID The EIP 165 interface ID.
* @param implementer The address of a contract that implements this interface for this node.
*/
function setInterface(bytes32 node, bytes4 interfaceID, address implementer) virtual external authorised(node) {
interfaces[node][interfaceID] = implementer;
emit InterfaceChanged(node, interfaceID, implementer);
}
/**
* Returns the address of a contract that implements the specified interface for this name.
* If an implementer has not been set for this interfaceID and name, the resolver will query
* the contract at `addr()`. If `addr()` is set, a contract exists at that address, and that
* contract implements EIP165 and returns `true` for the specified interfaceID, its address
* will be returned.
* @param node The ENS node to query.
* @param interfaceID The EIP 165 interface ID to check for.
* @return The address that implements this interface, or 0 if the interface is unsupported.
*/
function interfaceImplementer(bytes32 node, bytes4 interfaceID) virtual override external view returns (address) {
address implementer = interfaces[node][interfaceID];
if(implementer != address(0)) {
return implementer;
}
address a = addr(node);
if(a == address(0)) {
return address(0);
}
(bool success, bytes memory returnData) = a.staticcall(abi.encodeWithSignature("supportsInterface(bytes4)", type(ISupportsInterface).interfaceId));
if(!success || returnData.length < 32 || returnData[31] == 0) {
// EIP 165 not supported by target
return address(0);
}
(success, returnData) = a.staticcall(abi.encodeWithSignature("supportsInterface(bytes4)", interfaceID));
if(!success || returnData.length < 32 || returnData[31] == 0) {
// Specified interface not supported by target
return address(0);
}
return a;
}
function supportsInterface(bytes4 interfaceID) virtual override public pure returns(bool) {
return interfaceID == type(IInterfaceResolver).interfaceId || super.supportsInterface(interfaceID);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
import "../ResolverBase.sol";
import "./INameResolver.sol";
abstract contract NameResolver is INameResolver, ResolverBase {
mapping(bytes32=>string) names;
/**
* Sets the name associated with an ENS node, for reverse records.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
*/
function setName(bytes32 node, string calldata newName) virtual external authorised(node) {
names[node] = newName;
emit NameChanged(node, newName);
}
/**
* Returns the name associated with an ENS node, for reverse records.
* Defined in EIP181.
* @param node The ENS node to query.
* @return The associated name.
*/
function name(bytes32 node) virtual override external view returns (string memory) {
return names[node];
}
function supportsInterface(bytes4 interfaceID) virtual override public pure returns(bool) {
return interfaceID == type(INameResolver).interfaceId || super.supportsInterface(interfaceID);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
import "../ResolverBase.sol";
import "./IPubkeyResolver.sol";
abstract contract PubkeyResolver is IPubkeyResolver, ResolverBase {
struct PublicKey {
bytes32 x;
bytes32 y;
}
mapping(bytes32=>PublicKey) pubkeys;
/**
* Sets the SECP256k1 public key associated with an ENS node.
* @param node The ENS node to query
* @param x the X coordinate of the curve point for the public key.
* @param y the Y coordinate of the curve point for the public key.
*/
function setPubkey(bytes32 node, bytes32 x, bytes32 y) virtual external authorised(node) {
pubkeys[node] = PublicKey(x, y);
emit PubkeyChanged(node, x, y);
}
/**
* Returns the SECP256k1 public key associated with an ENS node.
* Defined in EIP 619.
* @param node The ENS node to query
* @return x The X coordinate of the curve point for the public key.
* @return y The Y coordinate of the curve point for the public key.
*/
function pubkey(bytes32 node) virtual override external view returns (bytes32 x, bytes32 y) {
return (pubkeys[node].x, pubkeys[node].y);
}
function supportsInterface(bytes4 interfaceID) virtual override public pure returns(bool) {
return interfaceID == type(IPubkeyResolver).interfaceId || super.supportsInterface(interfaceID);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
import "../ResolverBase.sol";
import "./ITextResolver.sol";
abstract contract TextResolver is ITextResolver, ResolverBase {
mapping(bytes32=>mapping(string=>string)) texts;
/**
* Sets the text data associated with an ENS node and key.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @param key The key to set.
* @param value The text data value to set.
*/
function setText(bytes32 node, string calldata key, string calldata value) virtual external authorised(node) {
texts[node][key] = value;
emit TextChanged(node, key, key);
}
/**
* Returns the text data associated with an ENS node and key.
* @param node The ENS node to query.
* @param key The text data key to query.
* @return The associated text data.
*/
function text(bytes32 node, string calldata key) virtual override external view returns (string memory) {
return texts[node][key];
}
function supportsInterface(bytes4 interfaceID) virtual override public pure returns(bool) {
return interfaceID == type(ITextResolver).interfaceId || super.supportsInterface(interfaceID);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "./IMulticallable.sol";
import "./SupportsInterface.sol";
abstract contract Multicallable is IMulticallable, SupportsInterface {
function multicall(bytes[] calldata data) external override returns(bytes[] memory results) {
results = new bytes[](data.length);
for(uint i = 0; i < data.length; i++) {
(bool success, bytes memory result) = address(this).delegatecall(data[i]);
require(success);
results[i] = result;
}
return results;
}
function supportsInterface(bytes4 interfaceID) public override virtual pure returns(bool) {
return interfaceID == type(IMulticallable).interfaceId || super.supportsInterface(interfaceID);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
import "./IABIResolver.sol";
import "../ResolverBase.sol";
interface IABIResolver {
event ABIChanged(bytes32 indexed node, uint256 indexed contentType);
/**
* Returns the ABI associated with an ENS node.
* Defined in EIP205.
* @param node The ENS node to query
* @param contentTypes A bitwise OR of the ABI formats accepted by the caller.
* @return contentType The content type of the return value
* @return data The ABI data
*/
function ABI(bytes32 node, uint256 contentTypes) external view returns (uint256, bytes memory);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
import "./SupportsInterface.sol";
abstract contract ResolverBase is SupportsInterface {
function isAuthorised(bytes32 node) internal virtual view returns(bool);
modifier authorised(bytes32 node) {
require(isAuthorised(node));
_;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
/**
* Interface for the legacy (ETH-only) addr function.
*/
interface IAddrResolver {
event AddrChanged(bytes32 indexed node, address a);
/**
* Returns the address associated with an ENS node.
* @param node The ENS node to query.
* @return The associated address.
*/
function addr(bytes32 node) external view returns (address payable);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
/**
* Interface for the new (multicoin) addr function.
*/
interface IAddressResolver {
event AddressChanged(bytes32 indexed node, uint coinType, bytes newAddress);
function addr(bytes32 node, uint coinType) external view returns(bytes memory);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
interface IContentHashResolver {
event ContenthashChanged(bytes32 indexed node, bytes hash);
/**
* Returns the contenthash associated with an ENS node.
* @param node The ENS node to query.
* @return The associated contenthash.
*/
function contenthash(bytes32 node) external view returns (bytes memory);
}pragma solidity ^0.8.4;
import "./BytesUtils.sol";
import "@ensdomains/buffer/contracts/Buffer.sol";
/**
* @dev RRUtils is a library that provides utilities for parsing DNS resource records.
*/
library RRUtils {
using BytesUtils for *;
using Buffer for *;
/**
* @dev Returns the number of bytes in the DNS name at 'offset' in 'self'.
* @param self The byte array to read a name from.
* @param offset The offset to start reading at.
* @return The length of the DNS name at 'offset', in bytes.
*/
function nameLength(bytes memory self, uint offset) internal pure returns(uint) {
uint idx = offset;
while (true) {
assert(idx < self.length);
uint labelLen = self.readUint8(idx);
idx += labelLen + 1;
if (labelLen == 0) {
break;
}
}
return idx - offset;
}
/**
* @dev Returns a DNS format name at the specified offset of self.
* @param self The byte array to read a name from.
* @param offset The offset to start reading at.
* @return ret The name.
*/
function readName(bytes memory self, uint offset) internal pure returns(bytes memory ret) {
uint len = nameLength(self, offset);
return self.substring(offset, len);
}
/**
* @dev Returns the number of labels in the DNS name at 'offset' in 'self'.
* @param self The byte array to read a name from.
* @param offset The offset to start reading at.
* @return The number of labels in the DNS name at 'offset', in bytes.
*/
function labelCount(bytes memory self, uint offset) internal pure returns(uint) {
uint count = 0;
while (true) {
assert(offset < self.length);
uint labelLen = self.readUint8(offset);
offset += labelLen + 1;
if (labelLen == 0) {
break;
}
count += 1;
}
return count;
}
uint constant RRSIG_TYPE = 0;
uint constant RRSIG_ALGORITHM = 2;
uint constant RRSIG_LABELS = 3;
uint constant RRSIG_TTL = 4;
uint constant RRSIG_EXPIRATION = 8;
uint constant RRSIG_INCEPTION = 12;
uint constant RRSIG_KEY_TAG = 16;
uint constant RRSIG_SIGNER_NAME = 18;
struct SignedSet {
uint16 typeCovered;
uint8 algorithm;
uint8 labels;
uint32 ttl;
uint32 expiration;
uint32 inception;
uint16 keytag;
bytes signerName;
bytes data;
bytes name;
}
function readSignedSet(bytes memory data) internal pure returns(SignedSet memory self) {
self.typeCovered = data.readUint16(RRSIG_TYPE);
self.algorithm = data.readUint8(RRSIG_ALGORITHM);
self.labels = data.readUint8(RRSIG_LABELS);
self.ttl = data.readUint32(RRSIG_TTL);
self.expiration = data.readUint32(RRSIG_EXPIRATION);
self.inception = data.readUint32(RRSIG_INCEPTION);
self.keytag = data.readUint16(RRSIG_KEY_TAG);
self.signerName = readName(data, RRSIG_SIGNER_NAME);
self.data = data.substring(RRSIG_SIGNER_NAME + self.signerName.length, data.length - RRSIG_SIGNER_NAME - self.signerName.length);
}
function rrs(SignedSet memory rrset) internal pure returns(RRIterator memory) {
return iterateRRs(rrset.data, 0);
}
/**
* @dev An iterator over resource records.
*/
struct RRIterator {
bytes data;
uint offset;
uint16 dnstype;
uint16 class;
uint32 ttl;
uint rdataOffset;
uint nextOffset;
}
/**
* @dev Begins iterating over resource records.
* @param self The byte string to read from.
* @param offset The offset to start reading at.
* @return ret An iterator object.
*/
function iterateRRs(bytes memory self, uint offset) internal pure returns (RRIterator memory ret) {
ret.data = self;
ret.nextOffset = offset;
next(ret);
}
/**
* @dev Returns true iff there are more RRs to iterate.
* @param iter The iterator to check.
* @return True iff the iterator has finished.
*/
function done(RRIterator memory iter) internal pure returns(bool) {
return iter.offset >= iter.data.length;
}
/**
* @dev Moves the iterator to the next resource record.
* @param iter The iterator to advance.
*/
function next(RRIterator memory iter) internal pure {
iter.offset = iter.nextOffset;
if (iter.offset >= iter.data.length) {
return;
}
// Skip the name
uint off = iter.offset + nameLength(iter.data, iter.offset);
// Read type, class, and ttl
iter.dnstype = iter.data.readUint16(off);
off += 2;
iter.class = iter.data.readUint16(off);
off += 2;
iter.ttl = iter.data.readUint32(off);
off += 4;
// Read the rdata
uint rdataLength = iter.data.readUint16(off);
off += 2;
iter.rdataOffset = off;
iter.nextOffset = off + rdataLength;
}
/**
* @dev Returns the name of the current record.
* @param iter The iterator.
* @return A new bytes object containing the owner name from the RR.
*/
function name(RRIterator memory iter) internal pure returns(bytes memory) {
return iter.data.substring(iter.offset, nameLength(iter.data, iter.offset));
}
/**
* @dev Returns the rdata portion of the current record.
* @param iter The iterator.
* @return A new bytes object containing the RR's RDATA.
*/
function rdata(RRIterator memory iter) internal pure returns(bytes memory) {
return iter.data.substring(iter.rdataOffset, iter.nextOffset - iter.rdataOffset);
}
uint constant DNSKEY_FLAGS = 0;
uint constant DNSKEY_PROTOCOL = 2;
uint constant DNSKEY_ALGORITHM = 3;
uint constant DNSKEY_PUBKEY = 4;
struct DNSKEY {
uint16 flags;
uint8 protocol;
uint8 algorithm;
bytes publicKey;
}
function readDNSKEY(bytes memory data, uint offset, uint length) internal pure returns(DNSKEY memory self) {
self.flags = data.readUint16(offset + DNSKEY_FLAGS);
self.protocol = data.readUint8(offset + DNSKEY_PROTOCOL);
self.algorithm = data.readUint8(offset + DNSKEY_ALGORITHM);
self.publicKey = data.substring(offset + DNSKEY_PUBKEY, length - DNSKEY_PUBKEY);
}
uint constant DS_KEY_TAG = 0;
uint constant DS_ALGORITHM = 2;
uint constant DS_DIGEST_TYPE = 3;
uint constant DS_DIGEST = 4;
struct DS {
uint16 keytag;
uint8 algorithm;
uint8 digestType;
bytes digest;
}
function readDS(bytes memory data, uint offset, uint length) internal pure returns(DS memory self) {
self.keytag = data.readUint16(offset + DS_KEY_TAG);
self.algorithm = data.readUint8(offset + DS_ALGORITHM);
self.digestType = data.readUint8(offset + DS_DIGEST_TYPE);
self.digest = data.substring(offset + DS_DIGEST, length - DS_DIGEST);
}
struct NSEC3 {
uint8 hashAlgorithm;
uint8 flags;
uint16 iterations;
bytes salt;
bytes32 nextHashedOwnerName;
bytes typeBitmap;
}
uint constant NSEC3_HASH_ALGORITHM = 0;
uint constant NSEC3_FLAGS = 1;
uint constant NSEC3_ITERATIONS = 2;
uint constant NSEC3_SALT_LENGTH = 4;
uint constant NSEC3_SALT = 5;
function readNSEC3(bytes memory data, uint offset, uint length) internal pure returns(NSEC3 memory self) {
uint end = offset + length;
self.hashAlgorithm = data.readUint8(offset + NSEC3_HASH_ALGORITHM);
self.flags = data.readUint8(offset + NSEC3_FLAGS);
self.iterations = data.readUint16(offset + NSEC3_ITERATIONS);
uint8 saltLength = data.readUint8(offset + NSEC3_SALT_LENGTH);
offset = offset + NSEC3_SALT;
self.salt = data.substring(offset, saltLength);
offset += saltLength;
uint8 nextLength = data.readUint8(offset);
require(nextLength <= 32);
offset += 1;
self.nextHashedOwnerName = data.readBytesN(offset, nextLength);
offset += nextLength;
self.typeBitmap = data.substring(offset, end - offset);
}
function checkTypeBitmap(NSEC3 memory self, uint16 rrtype) internal pure returns(bool) {
return checkTypeBitmap(self.typeBitmap, 0, rrtype);
}
/**
* @dev Checks if a given RR type exists in a type bitmap.
* @param bitmap The byte string to read the type bitmap from.
* @param offset The offset to start reading at.
* @param rrtype The RR type to check for.
* @return True if the type is found in the bitmap, false otherwise.
*/
function checkTypeBitmap(bytes memory bitmap, uint offset, uint16 rrtype) internal pure returns (bool) {
uint8 typeWindow = uint8(rrtype >> 8);
uint8 windowByte = uint8((rrtype & 0xff) / 8);
uint8 windowBitmask = uint8(uint8(1) << (uint8(7) - uint8(rrtype & 0x7)));
for (uint off = offset; off < bitmap.length;) {
uint8 window = bitmap.readUint8(off);
uint8 len = bitmap.readUint8(off + 1);
if (typeWindow < window) {
// We've gone past our window; it's not here.
return false;
} else if (typeWindow == window) {
// Check this type bitmap
if (len <= windowByte) {
// Our type is past the end of the bitmap
return false;
}
return (bitmap.readUint8(off + windowByte + 2) & windowBitmask) != 0;
} else {
// Skip this type bitmap
off += len + 2;
}
}
return false;
}
function compareNames(bytes memory self, bytes memory other) internal pure returns (int) {
if (self.equals(other)) {
return 0;
}
uint off;
uint otheroff;
uint prevoff;
uint otherprevoff;
uint counts = labelCount(self, 0);
uint othercounts = labelCount(other, 0);
// Keep removing labels from the front of the name until both names are equal length
while (counts > othercounts) {
prevoff = off;
off = progress(self, off);
counts--;
}
while (othercounts > counts) {
otherprevoff = otheroff;
otheroff = progress(other, otheroff);
othercounts--;
}
// Compare the last nonequal labels to each other
while (counts > 0 && !self.equals(off, other, otheroff)) {
prevoff = off;
off = progress(self, off);
otherprevoff = otheroff;
otheroff = progress(other, otheroff);
counts -= 1;
}
if (off == 0) {
return -1;
}
if(otheroff == 0) {
return 1;
}
return self.compare(prevoff + 1, self.readUint8(prevoff), other, otherprevoff + 1, other.readUint8(otherprevoff));
}
/**
* @dev Compares two serial numbers using RFC1982 serial number math.
*/
function serialNumberGte(uint32 i1, uint32 i2) internal pure returns(bool) {
return int32(i1) - int32(i2) >= 0;
}
function progress(bytes memory body, uint off) internal pure returns(uint) {
return off + 1 + body.readUint8(off);
}
/**
* @dev Computes the keytag for a chunk of data.
* @param data The data to compute a keytag for.
* @return The computed key tag.
*/
function computeKeytag(bytes memory data) internal pure returns (uint16) {
/* This function probably deserves some explanation.
* The DNSSEC keytag function is a checksum that relies on summing up individual bytes
* from the input string, with some mild bitshifting. Here's a Naive solidity implementation:
*
* function computeKeytag(bytes memory data) internal pure returns (uint16) {
* uint ac;
* for (uint i = 0; i < data.length; i++) {
* ac += i & 1 == 0 ? uint16(data.readUint8(i)) << 8 : data.readUint8(i);
* }
* return uint16(ac + (ac >> 16));
* }
*
* The EVM, with its 256 bit words, is exceedingly inefficient at doing byte-by-byte operations;
* the code above, on reasonable length inputs, consumes over 100k gas. But we can make the EVM's
* large words work in our favour.
*
* The code below works by treating the input as a series of 256 bit words. It first masks out
* even and odd bytes from each input word, adding them to two separate accumulators `ac1` and `ac2`.
* The bytes are separated by empty bytes, so as long as no individual sum exceeds 2^16-1, we're
* effectively summing 16 different numbers with each EVM ADD opcode.
*
* Once it's added up all the inputs, it has to add all the 16 bit values in `ac1` and `ac2` together.
* It does this using the same trick - mask out every other value, shift to align them, add them together.
* After the first addition on both accumulators, there's enough room to add the two accumulators together,
* and the remaining sums can be done just on ac1.
*/
unchecked {
require(data.length <= 8192, "Long keys not permitted");
uint ac1;
uint ac2;
for(uint i = 0; i < data.length + 31; i += 32) {
uint word;
assembly {
word := mload(add(add(data, 32), i))
}
if(i + 32 > data.length) {
uint unused = 256 - (data.length - i) * 8;
word = (word >> unused) << unused;
}
ac1 += (word & 0xFF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00) >> 8;
ac2 += (word & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF);
}
ac1 = (ac1 & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF)
+ ((ac1 & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16);
ac2 = (ac2 & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF)
+ ((ac2 & 0xFFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000) >> 16);
ac1 = (ac1 << 8) + ac2;
ac1 = (ac1 & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF)
+ ((ac1 & 0xFFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000) >> 32);
ac1 = (ac1 & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF)
+ ((ac1 & 0xFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF0000000000000000) >> 64);
ac1 = (ac1 & 0x00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
+ (ac1 >> 128);
ac1 += (ac1 >> 16) & 0xFFFF;
return uint16(ac1);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
interface IDNSRecordResolver {
// DNSRecordChanged is emitted whenever a given node/name/resource's RRSET is updated.
event DNSRecordChanged(bytes32 indexed node, bytes name, uint16 resource, bytes record);
// DNSRecordDeleted is emitted whenever a given node/name/resource's RRSET is deleted.
event DNSRecordDeleted(bytes32 indexed node, bytes name, uint16 resource);
// DNSZoneCleared is emitted whenever a given node's zone information is cleared.
event DNSZoneCleared(bytes32 indexed node);
/**
* Obtain a DNS record.
* @param node the namehash of the node for which to fetch the record
* @param name the keccak-256 hash of the fully-qualified name for which to fetch the record
* @param resource the ID of the resource as per https://en.wikipedia.org/wiki/List_of_DNS_record_types
* @return the DNS record in wire format if present, otherwise empty
*/
function dnsRecord(bytes32 node, bytes32 name, uint16 resource) external view returns (bytes memory);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
interface IDNSZoneResolver {
// DNSZonehashChanged is emitted whenever a given node's zone hash is updated.
event DNSZonehashChanged(bytes32 indexed node, bytes lastzonehash, bytes zonehash);
/**
* zonehash obtains the hash for the zone.
* @param node The ENS node to query.
* @return The associated contenthash.
*/
function zonehash(bytes32 node) external view returns (bytes memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
interface ISupportsInterface {
function supportsInterface(bytes4 interfaceID) external pure returns(bool);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
interface IInterfaceResolver {
event InterfaceChanged(bytes32 indexed node, bytes4 indexed interfaceID, address implementer);
/**
* Returns the address of a contract that implements the specified interface for this name.
* If an implementer has not been set for this interfaceID and name, the resolver will query
* the contract at `addr()`. If `addr()` is set, a contract exists at that address, and that
* contract implements EIP165 and returns `true` for the specified interfaceID, its address
* will be returned.
* @param node The ENS node to query.
* @param interfaceID The EIP 165 interface ID to check for.
* @return The address that implements this interface, or 0 if the interface is unsupported.
*/
function interfaceImplementer(bytes32 node, bytes4 interfaceID) external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
interface INameResolver {
event NameChanged(bytes32 indexed node, string name);
/**
* Returns the name associated with an ENS node, for reverse records.
* Defined in EIP181.
* @param node The ENS node to query.
* @return The associated name.
*/
function name(bytes32 node) external view returns (string memory);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
interface IPubkeyResolver {
event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y);
/**
* Returns the SECP256k1 public key associated with an ENS node.
* Defined in EIP 619.
* @param node The ENS node to query
* @return x The X coordinate of the curve point for the public key.
* @return y The Y coordinate of the curve point for the public key.
*/
function pubkey(bytes32 node) external view returns (bytes32 x, bytes32 y);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
interface ITextResolver {
event TextChanged(bytes32 indexed node, string indexed indexedKey, string key);
/**
* Returns the text data associated with an ENS node and key.
* @param node The ENS node to query.
* @param key The text data key to query.
* @return The associated text data.
*/
function text(bytes32 node, string calldata key) external view returns (string memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
interface IMulticallable {
function multicall(bytes[] calldata data) external returns(bytes[] memory results);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "./ISupportsInterface.sol";
abstract contract SupportsInterface is ISupportsInterface {
function supportsInterface(bytes4 interfaceID) virtual override public pure returns(bool) {
return interfaceID == type(ISupportsInterface).interfaceId;
}
}pragma solidity ^0.8.4;
library BytesUtils {
/*
* @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.
*/
function keccak(bytes memory self, uint offset, uint len) internal pure returns (bytes32 ret) {
require(offset + len <= self.length);
assembly {
ret := keccak256(add(add(self, 32), offset), len)
}
}
/*
* @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.
*/
function compare(bytes memory self, bytes memory other) internal pure returns (int) {
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.
*/
function compare(bytes memory self, uint offset, uint len, bytes memory other, uint otheroffset, uint otherlen) internal pure returns (int) {
uint shortest = len;
if (otherlen < len)
shortest = otherlen;
uint selfptr;
uint otherptr;
assembly {
selfptr := add(self, add(offset, 32))
otherptr := add(other, add(otheroffset, 32))
}
for (uint idx = 0; idx < shortest; idx += 32) {
uint a;
uint b;
assembly {
a := mload(selfptr)
b := mload(otherptr)
}
if (a != b) {
// Mask out irrelevant bytes and check again
uint mask;
if (shortest > 32) {
mask = type(uint256).max;
} else {
mask = ~(2 ** (8 * (32 - shortest + idx)) - 1);
}
int diff = int(a & mask) - int(b & mask);
if (diff != 0)
return diff;
}
selfptr += 32;
otherptr += 32;
}
return int(len) - int(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.
*/
function equals(bytes memory self, uint offset, bytes memory other, uint otherOffset, uint len) internal pure returns (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.
*/
function equals(bytes memory self, uint offset, bytes memory other, uint otherOffset) internal pure returns (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.
*/
function equals(bytes memory self, uint offset, bytes memory other) internal pure returns (bool) {
return self.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.
*/
function equals(bytes memory self, bytes memory other) internal pure returns(bool) {
return self.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.
*/
function readUint8(bytes memory self, uint idx) internal pure returns (uint8 ret) {
return uint8(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.
*/
function readUint16(bytes memory self, uint idx) internal pure returns (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.
*/
function readUint32(bytes memory self, uint idx) internal pure returns (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.
*/
function readBytes32(bytes memory self, uint idx) internal pure returns (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.
*/
function readBytes20(bytes memory self, uint idx) internal pure returns (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.
*/
function readBytesN(bytes memory self, uint idx, uint len) internal pure returns (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)
}
}
function memcpy(uint dest, uint src, uint len) private pure {
// Copy word-length chunks while possible
for (; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
dest += 32;
src += 32;
}
// Copy remaining bytes
unchecked {
uint 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.
*/
function substring(bytes memory self, uint offset, uint len) internal pure returns(bytes memory) {
require(offset + len <= self.length);
bytes memory ret = new bytes(len);
uint dest;
uint 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.
bytes constant 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.
*/
function base32HexDecodeWord(bytes memory self, uint off, uint len) internal pure returns(bytes32) {
require(len <= 52);
uint ret = 0;
uint8 decoded;
for(uint i = 0; i < len; i++) {
bytes1 char = self[off + i];
require(char >= 0x30 && char <= 0x7A);
decoded = uint8(base32HexTable[uint(uint8(char)) - 0x30]);
require(decoded <= 0x20);
if(i == len - 1) {
break;
}
ret = (ret << 5) | decoded;
}
uint bitlen = len * 5;
if(len % 8 == 0) {
// Multiple of 8 characters, no padding
ret = (ret << 5) | decoded;
} else if(len % 8 == 2) {
// Two extra characters - 1 byte
ret = (ret << 3) | (decoded >> 2);
bitlen -= 2;
} else if(len % 8 == 4) {
// Four extra characters - 2 bytes
ret = (ret << 1) | (decoded >> 4);
bitlen -= 4;
} else if(len % 8 == 5) {
// Five extra characters - 3 bytes
ret = (ret << 4) | (decoded >> 1);
bitlen -= 1;
} else if(len % 8 == 7) {
// Seven extra characters - 4 bytes
ret = (ret << 2) | (decoded >> 3);
bitlen -= 3;
} else {
revert();
}
return bytes32(ret << (256 - bitlen));
}
}// SPDX-License-Identifier: BSD-2-Clause
pragma solidity ^0.8.4;
/**
* @dev A library for working with mutable byte buffers in Solidity.
*
* Byte buffers are mutable and expandable, and provide a variety of primitives
* for appending to them. At any time you can fetch a bytes object containing the
* current contents of the buffer. The bytes object should not be stored between
* operations, as it may change due to resizing of the buffer.
*/
library Buffer {
/**
* @dev Represents a mutable buffer. Buffers have a current value (buf) and
* a capacity. The capacity may be longer than the current value, in
* which case it can be extended without the need to allocate more memory.
*/
struct buffer {
bytes buf;
uint capacity;
}
/**
* @dev Initializes a buffer with an initial capacity.
* @param buf The buffer to initialize.
* @param capacity The number of bytes of space to allocate the buffer.
* @return The buffer, for chaining.
*/
function init(buffer memory buf, uint capacity) internal pure returns(buffer memory) {
if (capacity % 32 != 0) {
capacity += 32 - (capacity % 32);
}
// Allocate space for the buffer data
buf.capacity = capacity;
assembly {
let ptr := mload(0x40)
mstore(buf, ptr)
mstore(ptr, 0)
let fpm := add(32, add(ptr, capacity))
if lt(fpm, ptr) {
revert(0, 0)
}
mstore(0x40, fpm)
}
return buf;
}
/**
* @dev Initializes a new buffer from an existing bytes object.
* Changes to the buffer may mutate the original value.
* @param b The bytes object to initialize the buffer with.
* @return A new buffer.
*/
function fromBytes(bytes memory b) internal pure returns(buffer memory) {
buffer memory buf;
buf.buf = b;
buf.capacity = b.length;
return buf;
}
function resize(buffer memory buf, uint capacity) private pure {
bytes memory oldbuf = buf.buf;
init(buf, capacity);
append(buf, oldbuf);
}
/**
* @dev Sets buffer length to 0.
* @param buf The buffer to truncate.
* @return The original buffer, for chaining..
*/
function truncate(buffer memory buf) internal pure returns (buffer memory) {
assembly {
let bufptr := mload(buf)
mstore(bufptr, 0)
}
return buf;
}
/**
* @dev Appends len bytes of a byte string to a buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @param len The number of bytes to copy.
* @return The original buffer, for chaining.
*/
function append(buffer memory buf, bytes memory data, uint len) internal pure returns(buffer memory) {
require(len <= data.length);
uint off = buf.buf.length;
uint newCapacity = off + len;
if (newCapacity > buf.capacity) {
resize(buf, newCapacity * 2);
}
uint dest;
uint src;
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Length of existing buffer data
let buflen := mload(bufptr)
// Start address = buffer address + offset + sizeof(buffer length)
dest := add(add(bufptr, 32), off)
// Update buffer length if we're extending it
if gt(newCapacity, buflen) {
mstore(bufptr, newCapacity)
}
src := add(data, 32)
}
// Copy word-length chunks while possible
for (; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
dest += 32;
src += 32;
}
// Copy remaining bytes
unchecked {
uint mask = (256 ** (32 - len)) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
return buf;
}
/**
* @dev Appends a byte string to a buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chaining.
*/
function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) {
return append(buf, data, data.length);
}
/**
* @dev Appends a byte to the buffer. Resizes if doing so would exceed the
* capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chaining.
*/
function appendUint8(buffer memory buf, uint8 data) internal pure returns(buffer memory) {
uint off = buf.buf.length;
uint offPlusOne = off + 1;
if (off >= buf.capacity) {
resize(buf, offPlusOne * 2);
}
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Address = buffer address + sizeof(buffer length) + off
let dest := add(add(bufptr, off), 32)
mstore8(dest, data)
// Update buffer length if we extended it
if gt(offPlusOne, mload(bufptr)) {
mstore(bufptr, offPlusOne)
}
}
return buf;
}
/**
* @dev Appends len bytes of bytes32 to a buffer. Resizes if doing so would
* exceed the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @param len The number of bytes to write (left-aligned).
* @return The original buffer, for chaining.
*/
function append(buffer memory buf, bytes32 data, uint len) private pure returns(buffer memory) {
uint off = buf.buf.length;
uint newCapacity = len + off;
if (newCapacity > buf.capacity) {
resize(buf, newCapacity * 2);
}
unchecked {
uint mask = (256 ** len) - 1;
// Right-align data
data = data >> (8 * (32 - len));
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Address = buffer address + sizeof(buffer length) + newCapacity
let dest := add(bufptr, newCapacity)
mstore(dest, or(and(mload(dest), not(mask)), data))
// Update buffer length if we extended it
if gt(newCapacity, mload(bufptr)) {
mstore(bufptr, newCapacity)
}
}
}
return buf;
}
/**
* @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chhaining.
*/
function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) {
return append(buf, bytes32(data), 20);
}
/**
* @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chaining.
*/
function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) {
return append(buf, data, 32);
}
/**
* @dev Appends a byte to the end of the buffer. Resizes if doing so would
* exceed the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @param len The number of bytes to write (right-aligned).
* @return The original buffer.
*/
function appendInt(buffer memory buf, uint data, uint len) internal pure returns(buffer memory) {
uint off = buf.buf.length;
uint newCapacity = len + off;
if (newCapacity > buf.capacity) {
resize(buf, newCapacity * 2);
}
unchecked {
uint mask = (256 ** len) - 1;
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Address = buffer address + sizeof(buffer length) + newCapacity
let dest := add(bufptr, newCapacity)
mstore(dest, or(and(mload(dest), not(mask)), data))
// Update buffer length if we extended it
if gt(newCapacity, mload(bufptr)) {
mstore(bufptr, newCapacity)
}
}
}
return buf;
}
}{
"remappings": [
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@aragon/osx/=lib/osx/packages/contracts/src/",
"@aragon/osx-commons-contracts/=lib/osx-commons/contracts/",
"@aragon/admin-plugin/=lib/admin-plugin/packages/contracts/src/",
"@aragon/multisig-plugin/=lib/multisig-plugin/packages/contracts/src/",
"@aragon/token-voting-plugin/=lib/token-voting-plugin/src/",
"@aragon/staged-proposal-processor-plugin/=lib/staged-proposal-processor-plugin/src/",
"@ensdomains/ens-contracts/=lib/ens-contracts/",
"@ensdomains/buffer/=lib/buffer/",
"forge-std/=lib/forge-std/src/",
"@openzeppelin/openzeppelin-foundry-upgrades/=lib/staged-proposal-processor-plugin/node_modules/@openzeppelin/openzeppelin-foundry-upgrades/src/",
"admin-plugin/=lib/admin-plugin/",
"buffer/=lib/buffer/contracts/",
"ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/",
"ens-contracts/=lib/ens-contracts/contracts/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"multisig-plugin/=lib/multisig-plugin/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/",
"osx-commons/=lib/osx-commons/",
"osx/=lib/osx/",
"plugin-version-1.3/=lib/token-voting-plugin/lib/plugin-version-1.3/packages/contracts/src/",
"solidity-stringutils/=lib/staged-proposal-processor-plugin/node_modules/solidity-stringutils/",
"staged-proposal-processor-plugin/=lib/staged-proposal-processor-plugin/src/",
"token-voting-plugin/=lib/token-voting-plugin/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract ENS","name":"_ens","type":"address"},{"internalType":"contract INameWrapper","name":"wrapperAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"contentType","type":"uint256"}],"name":"ABIChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"address","name":"a","type":"address"}],"name":"AddrChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"coinType","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"newAddress","type":"bytes"}],"name":"AddressChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"hash","type":"bytes"}],"name":"ContenthashChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"name","type":"bytes"},{"indexed":false,"internalType":"uint16","name":"resource","type":"uint16"},{"indexed":false,"internalType":"bytes","name":"record","type":"bytes"}],"name":"DNSRecordChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"name","type":"bytes"},{"indexed":false,"internalType":"uint16","name":"resource","type":"uint16"}],"name":"DNSRecordDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"DNSZoneCleared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"lastzonehash","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"zonehash","type":"bytes"}],"name":"DNSZonehashChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"bytes4","name":"interfaceID","type":"bytes4"},{"indexed":false,"internalType":"address","name":"implementer","type":"address"}],"name":"InterfaceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"string","name":"name","type":"string"}],"name":"NameChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"x","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"PubkeyChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"string","name":"indexedKey","type":"string"},{"indexed":false,"internalType":"string","name":"key","type":"string"}],"name":"TextChanged","type":"event"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"contentTypes","type":"uint256"}],"name":"ABI","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"addr","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"coinType","type":"uint256"}],"name":"addr","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"clearDNSZone","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"contenthash","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"name","type":"bytes32"},{"internalType":"uint16","name":"resource","type":"uint16"}],"name":"dnsRecord","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"name","type":"bytes32"}],"name":"hasDNSRecords","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"interfaceImplementer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"pubkey","outputs":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"contentType","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setABI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"uint256","name":"coinType","type":"uint256"},{"internalType":"bytes","name":"a","type":"bytes"}],"name":"setAddr","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"a","type":"address"}],"name":"setAddr","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes","name":"hash","type":"bytes"}],"name":"setContenthash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"setDNSRecords","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes4","name":"interfaceID","type":"bytes4"},{"internalType":"address","name":"implementer","type":"address"}],"name":"setInterface","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"newName","type":"string"}],"name":"setName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"name":"setPubkey","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"key","type":"string"},{"internalType":"string","name":"value","type":"string"}],"name":"setText","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"bytes","name":"hash","type":"bytes"}],"name":"setZonehash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"string","name":"key","type":"string"}],"name":"text","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"zonehash","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"}]Contract Creation Code
608034609357601f61258438819003918201601f19168301916001600160401b03831184841017609757808492604094855283398101031260935780516001600160a01b0381169190829003609357602001516001600160a01b038116919082900360935760018060a01b0319600b541617600b5560018060a01b0319600c541617600c556040516124d890816100ac8239f35b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f3560e01c806301ffc9a7146101b45780630af179d7146101af57806310f13a8c146101aa578063124a319c146101a55780632203ab56146101a057806329cd62ea1461019b578063304e6ade146101965780633b3b57de146101915780634cbf6ba41461018c57806359d1d43c146101875780635c98042b14610182578063623195b01461017d578063691f34311461017857806377372213146101735780638b95dd711461016e578063a22cb46514610169578063a8fa568214610164578063ac9650d81461015f578063ad5780af1461015a578063bc1c58d114610155578063c869023314610150578063ce3decdc1461014b578063d5fa2b0014610146578063e59d895d14610141578063e985e9c51461013c5763f1cb7e0614610137575f80fd5b6116c6565b611662565b6115b1565b611446565b6112e1565b6112a6565b611272565b61120f565b6111a3565b6110bb565b610fb3565b610df8565b610c54565b610c20565b610acb565b610a97565b610a39565b6109d9565b6109bb565b61087a565b6107e3565b6107b4565b610725565b61056d565b6103e5565b6101eb565b600435906001600160e01b0319821682036101d057565b5f80fd5b602435906001600160e01b0319821682036101d057565b346101d05760203660031901126101d0576102336001600160e01b03196102106101b9565b16631592ca1b60e31b8114801580610237575b6040518215158152806020810186565b0390f35b631674750f60e21b8314928315610253575b505050805f610223565b63c869023360e01b8114935090918315610273575b5050505f8080610249565b63691f343160e01b8214935090918315610293575b5050505f8080610268565b6304928c6760e21b83149350909183156102b3575b5050505f8080610288565b63547d2b4160e11b8114935090918315610374575b83156102da575b5050505f80806102a8565b63bc1c58d160e01b82149350909183156102fa575b5050505f80806102cf565b631d9dabef60e11b8314935090918315610363575b8315610321575b5050505f80806102ef565b631101d5ab60e11b8114935090918315610341575b5050505f8080610316565b925090610352575b505f8080610336565b6301ffc9a760e01b1490505f610349565b6378e5bf0360e11b8114935061030f565b635c98042b60e01b821493506102c8565b9181601f840112156101d0578235916001600160401b0383116101d057602083818601950101116101d057565b9060406003198301126101d05760043591602435906001600160401b0382116101d0576103e191600401610385565b9091565b346101d0576103f3366103b2565b916103fd81611d72565b156101d0576060915f808461041b610416368987610dc2565b611ec0565b955b610435610431886020810151905151111590565b1590565b1561053c5761ffff8416806104a0575050509050610458604085015161ffff1690565b9061046285611ff6565b6040516020810190610486816104788486611730565b03601f198101835282610d86565b506104929050866122fa565b61049b87611f38565b61041d565b6104a988611ff6565b908960408a01916104c66104bf845161ffff1690565b61ffff1690565b14801590610529575b6104dc575b505050610492565b909261050d92956105159560208c01986105066104fa848c51611723565b9451159536908d610dc2565b918c612115565b5161ffff1690565b915190610521866122fa565b5f80896104d4565b506105376104318487612011565b6104cf565b9287949591805161054957005b61056561056b9761055a8689611723565b965115973691610dc2565b92612115565b005b346101d05760603660031901126101d0576004356024356001600160401b0381116101d0576105a0903690600401610385565b6044929192356001600160401b0381116101d0576105c2903690600401610385565b6105cb84611d72565b156101d057835f52600a60205260405f20602060405180928689833786820190815203019020916001600160401b038211610720576106148261060e855461174f565b8561179d565b5f90601f8311600114610693579180610666927fd8c9334b1a9c2f9da342a0a2b32629c1a229b6445dad78947f674b44444a75509695945f92610688575b50508160011b915f199060031b1c19161790565b90555b61067381856117e2565b9361068360405192839283611816565b0390a3005b013590505f80610652565b601f198316916106a6855f5260205f2090565b925f5b81811061070857509160019391857fd8c9334b1a9c2f9da342a0a2b32629c1a229b6445dad78947f674b44444a755098979694106106ef575b505050811b019055610669565b01355f19600384901b60f8161c191690555f80806106e2565b919360206001819287870135815501950192016106a9565b610d57565b346101d05760403660031901126101d057602061074c6004356107466101d4565b90611893565b6040516001600160a01b039091168152f35b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b90604061079a92603c8152816020820152019061075e565b90565b60409061079a93928152816020820152019061075e565b346101d05760403660031901126101d0576107d3602435600435611ab3565b906102336040519283928361079d565b346101d05760603660031901126101d05760043560243560443561080683611d72565b156101d0577f1d6f5e03d3f63eb58751986629a5439baee5079ff04f345becb66e23eb154e469160405161083981610d6b565b818152600160208201848152865f52600960205260405f2092518355519101556108756040519283928360209093929193604081019481520152565b0390a2005b346101d057610888366103b2565b610893839293611d72565b156101d057815f52600260205260405f20926001600160401b038211610720576108c7826108c1865461174f565b8661179d565b5f93601f83116001146109335761091683807fe379c1624ed7e714cc0937528a32359d69d5281337765313dba4e081b72d757896975f91610928575b508160011b915f199060031b1c19161790565b90555b61087560405192839283611816565b90508401355f610903565b601f19831694610946825f5260205f2090565b905f5b8781106109a35750847fe379c1624ed7e714cc0937528a32359d69d5281337765313dba4e081b72d757896971061098a575b5050600183811b019055610919565b8301355f19600386901b60f8161c191690555f8061097b565b90916020600181928588013581550193019101610949565b346101d05760203660031901126101d057602061074c600435611b2c565b346101d05760403660031901126101d0576004356024355f9182526006602090815260408084206004835281852054855282528084209284529181529181902054905161ffff90911615158152f35b90602061079a92818152019061075e565b346101d057610233610a7c610a836020610a52366103b2565b92915f52600a825260405f2083604051948593843782019081520301902060405192838092611a32565b0382610d86565b60405191829160208352602083019061075e565b346101d05760203660031901126101d0576004355f526003602052610233610a7c610a8360405f2060405192838092611a32565b346101d05760603660031901126101d0576004356024356044356001600160401b0381116101d057610b01903690600401610385565b610b0c849294611d72565b156101d0575f198301838111610c1b5783166101d057815f525f60205260405f20835f5260205260405f20906001600160401b03811161072057610b5a81610b54845461174f565b8461179d565b5f601f8211600114610bb2578190610b89939495965f926106885750508160011b915f199060031b1c19161790565b90555b7faa121bbeef5f32f5961a2a28966e769023910fc9479059ee3495d4c1a696efe35f80a3005b601f19821695610bc5845f5260205f2090565b915f5b888110610c0357508360019596979810610bea575b505050811b019055610b8c565b01355f19600384901b60f8161c191690555f8080610bdd565b90926020600181928686013581550194019101610bc8565b61170f565b346101d05760203660031901126101d0576004355f526008602052610233610a7c610a8360405f2060405192838092611a32565b346101d057610c62366103b2565b610c6d839293611d72565b156101d057815f52600860205260405f20926001600160401b03821161072057610c9b826108c1865461174f565b5f93601f8311600114610ce95761091683807fb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f796975f9161092857508160011b915f199060031b1c19161790565b601f19831694610cfc825f5260205f2090565b905f5b878110610d3f5750847fb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f796971061098a575050600183811b019055610919565b90916020600181928588013581550193019101610cff565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761072057604052565b90601f801991011681019081106001600160401b0382111761072057604052565b6001600160401b03811161072057601f01601f191660200190565b929192610dce82610da7565b91610ddc6040519384610d86565b8294818452818301116101d0578281602093845f960137010152565b346101d05760603660031901126101d0576004356024356044356001600160401b0381116101d057366023820112156101d057610e3f903690602481600401359101610dc2565b91610e4981611d72565b156101d057807f65412581168e88a1e60c6459d7f44ae83ad0832e670826c05a4e2476b57af75260405180610e7f87878361079d565b0390a2603c8214610f5f575b5f52600160205260405f20905f5260205260405f2081516001600160401b03811161072057610ebe81610b54845461174f565b602092601f8211600114610efc57610eed929382915f92610ef15750508160011b915f199060031b1c19161790565b9055005b015190505f80610652565b601f19821693610f0f845f5260205f2090565b915f5b868110610f475750836001959610610f2f575b505050811b019055005b01515f1960f88460031b161c191690555f8080610f25565b91926020600181928685015181550194019201610f12565b807f52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd26020610f8c8661231b565b6040516001600160a01b039091168152a2610e8b565b6001600160a01b038116036101d057565b346101d05760403660031901126101d057600435610fd081610fa2565b60243580151581036101d0576001600160a01b0382169133831461106457335f908152600d6020526040902061102e91839161101d91905b9060018060a01b03165f5260205260405f2090565b9060ff801983541691151516179055565b604051901515815233907f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31908060208101610683565b60405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b6064820152608490fd5b346101d05760603660031901126101d05760043560443560243561ffff821682036101d05761112c610a7c926111389285610233965f52600560205260405f20905f52600460205260405f20545f5260205260405f20905f5260205260405f209061ffff165f5260205260405f2090565b60405192838092611a32565b60405191829182610a28565b602081016020825282518091526040820191602060408360051b8301019401925f915b83831061117657505050505090565b9091929394602080611194600193603f19868203018752895161075e565b97019301930191939290611167565b346101d05760203660031901126101d0576004356001600160401b0381116101d057366023820112156101d0578060040135906001600160401b0382116101d0573660248360051b830101116101d0576102339160246112039201611c89565b60405191829182611144565b346101d05760203660031901126101d05760043561122c81611d72565b156101d057805f52600460205260405f2080545f198114610c1b5760010190557fb757169b8492ca2f1c6619d9d76ce22803035c3b1d5f6930dffe7b127c1a19835f80a2005b346101d05760203660031901126101d0576004355f526002602052610233610a7c610a8360405f2060405192838092611a32565b346101d05760203660031901126101d0576004355f908152600960209081526040918290208054600190910154835191825291810191909152f35b346101d0576112ef366103b2565b91906112fa82611d72565b156101d057815f526003602052610a7c61131d60405f2060405192838092611a32565b825f52600360205260405f206001600160401b0385116107205761134b85611345835461174f565b8361179d565b5f601f86116001146113b757946108759161139d82807f8f15ed4b723ef428f250961da8315675b507046737e19319fc1a4d81bfe87f8598995f916113ac57508160011b915f199060031b1c19161790565b90555b60405193849384611d2d565b90508701355f610903565b601f198616906113ca835f5260205f2090565b915f5b81811061142e5750916108759391887f8f15ed4b723ef428f250961da8315675b507046737e19319fc1a4d81bfe87f8598999410611415575b5050600182811b0190556113a0565b8601355f19600385901b60f8161c191690555f80611406565b9192602060018192868a0135815501940192016113cd565b346101d05760403660031901126101d05760243560043561146682610fa2565b61146f81611d72565b156101d05761147c61232e565b9160601b602083015261148e81611d72565b156101d057807f65412581168e88a1e60c6459d7f44ae83ad0832e670826c05a4e2476b57af752604051806114c38682610782565b0390a2807f52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd260206114f38561231b565b6040516001600160a01b039091168152a25f52600160205260405f20603c5f5260205260405f2081516001600160401b0381116107205761153881610b54845461174f565b602092601f821160011461156757610eed929382915f92610ef15750508160011b915f199060031b1c19161790565b601f1982169361157a845f5260205f2090565b915f5b8681106115995750836001959610610f2f57505050811b019055005b9192602060018192868501518155019401920161157d565b346101d05760603660031901126101d0576004356115cd6101d4565b90604435916115db83610fa2565b6115e482611d72565b156101d05760207f7c69f06bea0bdef565b709e93a147836b0063ba2dd89f02d0b7e8d931e6a6daa91835f52600782526116328160405f209063ffffffff60e01b165f5260205260405f2090565b80546001600160a01b0319166001600160a01b0390961695861790556040519485526001600160e01b03191693a3005b346101d05760403660031901126101d057602060ff6116ba60043561168681610fa2565b6024359061169382610fa2565b60018060a01b03165f52600d845260405f209060018060a01b03165f5260205260405f2090565b54166040519015158152f35b346101d05760403660031901126101d057600435602435905f52600160205260405f20905f52602052610233610a7c610a8360405f2060405192838092611a32565b156101d057565b634e487b7160e01b5f52601160045260245ffd5b91908203918211610c1b57565b805191908290602001825e015f815290565b908092918237015f815290565b90600182811c9216801561177d575b602083101461176957565b634e487b7160e01b5f52602260045260245ffd5b91607f169161175e565b818110611792575050565b5f8155600101611787565b9190601f81116117ac57505050565b6117d6925f5260205f20906020601f840160051c830193106117d8575b601f0160051c0190611787565b565b90915081906117c9565b81604051928392833781015f815203902090565b908060209392818452848401375f828201840152601f01601f1916010190565b91602061079a9381815201916117f6565b60405190611836602083610d86565b5f8252565b3d15611865573d9061184c82610da7565b9161185a6040519384610d86565b82523d5f602084013e565b606090565b634e487b7160e01b5f52603260045260245ffd5b8051601f101561188e57603f0190565b61186a565b6118cf6118c2836118ac845f52600760205260405f2090565b9063ffffffff60e01b165f5260205260405f2090565b546001600160a01b031690565b6001600160a01b038116611a2257506118ea6118f691611b2c565b6001600160a01b031690565b906001600160a01b038216156119ef576040516301ffc9a760e01b6020820181815260248301919091525f918291906119328160448101610478565b5190855afa61193f61183b565b9015908115611a15575b81156119f5575b506119ef576040516301ffc9a760e01b602082019081526001600160e01b031990921660248201525f9182916119898160448101610478565b5190845afa61199661183b565b90159081156119e2575b81156119b4575b506119af5790565b505f90565b6001600160f81b031991506119da906119cc9061187e565b516001600160f81b03191690565b16155f6119a7565b90506020815110906119a0565b50505f90565b6001600160f81b03199150611a0d906119cc9061187e565b16155f611950565b9050602081511090611949565b91505090565b61079a905461174f565b5f9291815491611a418361174f565b8083529260018116908115611a965750600114611a5d57505050565b5f9081526020812093945091925b838310611a7c575060209250010190565b600181602092949394548385870101520191019190611a6b565b915050602093945060ff929192191683830152151560051b010190565b9190915f525f60205260405f2060015b83811115611adb5750509050611ad7611827565b5f91565b838116151580611b10575b611af25760011b611ac3565b8093505f52602052610a7c61079a60405f2060405192838092611a32565b50805f5281602052611b2560405f205461174f565b1515611ae6565b5f52600160205260405f20603c5f52602052610a7c611b5460405f2060405192838092611a32565b8051156119af5761079a9061231b565b91909182516001600160401b03811161072057611b8581610b54845461174f565b6020601f8211600114611bb8578190611bb49394955f92610ef15750508160011b915f199060031b1c19161790565b9055565b601f19821690611bcb845f5260205f2090565b915f5b818110611c0557509583600195969710611bed575b505050811b019055565b01515f1960f88460031b161c191690555f8080611be3565b9192602060018192868b015181550194019201611bce565b6001600160401b0381116107205760051b60200190565b919081101561188e5760051b81013590601e19813603018212156101d05701908135916001600160401b0383116101d05760200182360381136101d0579190565b805182101561188e5760209160051b010190565b611c9282611c1d565b91611ca06040519384610d86565b808352601f19611caf82611c1d565b015f5b818110611d1c5750505f5b818110611cca5750505090565b805f80611cda6001948688611c34565b90611cea60405180938193611742565b0390305af4611d00611cfa61183b565b91611708565b611d0a8287611c75565b52611d158186611c75565b5001611cbd565b806060602080938801015201611cb2565b91611d4461079a949260408552604085019061075e565b9260208185039101526117f6565b908160209103126101d0575161079a81610fa2565b6040513d5f823e3d90fd5b600b54611d87906001600160a01b03166118ea565b6040516302571be360e01b8152600481018390529190602090839060249082905afa918215611e9a575f92611e9f575b50600c548290611dcf906001600160a01b03166118ea565b906001600160a01b0382166001600160a01b0390911614611e31575b50506001600160a01b0381163314908115611e04575090565b6001600160a01b03165f908152600d6020526040902061079a9150611e2a903390611008565b5460ff1690565b6040516331a9108f60e11b81526004810192909252909150602090829060249082905afa908115611e9a575f91611e6b575b505f80611deb565b611e8d915060203d602011611e93575b611e858183610d86565b810190611d52565b5f611e63565b503d611e7b565b611d67565b611eb991925060203d602011611e9357611e858183610d86565b905f611db7565b9060405160e08101908082106001600160401b03831117610720576117d6916040525f60208201525f60408201525f60608201525f60808201525f60a0820152809381525f60c0820152611f38565b9060028201809211610c1b57565b9060048201809211610c1b57565b91908201809211610c1b57565b60c081019081519081602082015280518051831015611ff05782611f5b91612382565b8201809211610c1b5760a0611fca611faa611f9185611f8c611f81611fec9888516123d9565b61ffff166040880152565b611f0f565b611f8c611f9f8287516123d9565b61ffff166060870152565b611fc5611fb88286516123f7565b63ffffffff166080860152565b611f1d565b91611fe2611fdc6104bf8584516123d9565b93611f0f565b9182910152611f2b565b9052565b50505050565b61079a906020815191015161200b8183612382565b91612417565b908151815181149283612025575b50505090565b61203b9293508161203591612493565b92612493565b145f808061201f565b61ffff1661ffff8114610c1b5760010190565b61ffff61207061079a959360608452606084019061075e565b93166020820152604081840391015261075e565b61ffff168015610c1b575f190190565b61209e815461174f565b90816120a8575050565b81601f5f93116001146120b9575055565b818352602083206120d591601f0160051c810190600101611787565b808252602082209081548360011b9084198560031b1c191617905555565b9061ffff61210e60209295949560408552604085019061075e565b9416910152565b6121418197929496959395612132835f52600460205260405f2090565b54948651602088012098612417565b911561223b576121da91506121ab8661219e858481846121c16121bc8d7f03528ed0c2a3ebc993b12ce3c16bb382f9c7d88ef7d8a1bf290eaf35955a12079f6121ab9061219e6121df9f61219e859f5f52600560205260405f2090565b905f5260205260405f2090565b9061ffff165f5260205260405f2090565b611a28565b6121f3575b505061219e905f52600560205260405f2090565b612094565b6121ee604051928392836120f3565b0390a2565b61219e61220f9261219e612233955f52600660205260405f2090565b61222361221e825461ffff1690565b612084565b61ffff1661ffff19825416179055565b8a81846121c6565b816122aa866121ab8961219e8861219e886122977f52a608b3303a48862d07a73d82fa221318c0027fbbcfb1b2329bface3f19ff2b9f886121ab6121ee9f9261219e6122af9f9461219e6121bc965f52600560205260405f2090565b156122bb575f52600560205260405f2090565b611b64565b60405193849384612057565b6122ec6122d88661219e8661219e865f52600660205260405f2090565b6122236122e7825461ffff1690565b612044565b5f52600560205260405f2090565b80519060c060a082015191015190808203918211610c1b5761079a92612417565b60148151036101d0576020015160601c90565b6040805190919061233f8382610d86565b6014815291601f1901366020840137565b9061235a82610da7565b6123676040519182610d86565b8281528092612378601f1991610da7565b0190602036910137565b81905b80518310156123c557805183101561188e576020838201015160f81c9260018401808511610c1b578101809111610c1b5792612385575061079a91611723565b634e487b7160e01b5f52600160045260245ffd5b60028201808311610c1b578151106101d057016002015161ffff1690565b60048201808311610c1b578151106101d057016004015163ffffffff1690565b90828101808211610c1b578251106101d05760209061243584612350565b9392010160208301915b6020811015612463575f19906020036101000a019081199051169082511617905290565b90918251815260208101809111610c1b579160208101809111610c1b5790601f1981019081111561243f5761170f565b805182116101d057602001209056fea2646970667358221220d30fd8dfb138ad46feae6d06db38e227664de28eb7d99f86917118387d46f23b64736f6c634300081c00330000000000000000000000008a788f1daa51b1a31bee0de197d06b7c084f89610000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x60806040526004361015610011575f80fd5b5f3560e01c806301ffc9a7146101b45780630af179d7146101af57806310f13a8c146101aa578063124a319c146101a55780632203ab56146101a057806329cd62ea1461019b578063304e6ade146101965780633b3b57de146101915780634cbf6ba41461018c57806359d1d43c146101875780635c98042b14610182578063623195b01461017d578063691f34311461017857806377372213146101735780638b95dd711461016e578063a22cb46514610169578063a8fa568214610164578063ac9650d81461015f578063ad5780af1461015a578063bc1c58d114610155578063c869023314610150578063ce3decdc1461014b578063d5fa2b0014610146578063e59d895d14610141578063e985e9c51461013c5763f1cb7e0614610137575f80fd5b6116c6565b611662565b6115b1565b611446565b6112e1565b6112a6565b611272565b61120f565b6111a3565b6110bb565b610fb3565b610df8565b610c54565b610c20565b610acb565b610a97565b610a39565b6109d9565b6109bb565b61087a565b6107e3565b6107b4565b610725565b61056d565b6103e5565b6101eb565b600435906001600160e01b0319821682036101d057565b5f80fd5b602435906001600160e01b0319821682036101d057565b346101d05760203660031901126101d0576102336001600160e01b03196102106101b9565b16631592ca1b60e31b8114801580610237575b6040518215158152806020810186565b0390f35b631674750f60e21b8314928315610253575b505050805f610223565b63c869023360e01b8114935090918315610273575b5050505f8080610249565b63691f343160e01b8214935090918315610293575b5050505f8080610268565b6304928c6760e21b83149350909183156102b3575b5050505f8080610288565b63547d2b4160e11b8114935090918315610374575b83156102da575b5050505f80806102a8565b63bc1c58d160e01b82149350909183156102fa575b5050505f80806102cf565b631d9dabef60e11b8314935090918315610363575b8315610321575b5050505f80806102ef565b631101d5ab60e11b8114935090918315610341575b5050505f8080610316565b925090610352575b505f8080610336565b6301ffc9a760e01b1490505f610349565b6378e5bf0360e11b8114935061030f565b635c98042b60e01b821493506102c8565b9181601f840112156101d0578235916001600160401b0383116101d057602083818601950101116101d057565b9060406003198301126101d05760043591602435906001600160401b0382116101d0576103e191600401610385565b9091565b346101d0576103f3366103b2565b916103fd81611d72565b156101d0576060915f808461041b610416368987610dc2565b611ec0565b955b610435610431886020810151905151111590565b1590565b1561053c5761ffff8416806104a0575050509050610458604085015161ffff1690565b9061046285611ff6565b6040516020810190610486816104788486611730565b03601f198101835282610d86565b506104929050866122fa565b61049b87611f38565b61041d565b6104a988611ff6565b908960408a01916104c66104bf845161ffff1690565b61ffff1690565b14801590610529575b6104dc575b505050610492565b909261050d92956105159560208c01986105066104fa848c51611723565b9451159536908d610dc2565b918c612115565b5161ffff1690565b915190610521866122fa565b5f80896104d4565b506105376104318487612011565b6104cf565b9287949591805161054957005b61056561056b9761055a8689611723565b965115973691610dc2565b92612115565b005b346101d05760603660031901126101d0576004356024356001600160401b0381116101d0576105a0903690600401610385565b6044929192356001600160401b0381116101d0576105c2903690600401610385565b6105cb84611d72565b156101d057835f52600a60205260405f20602060405180928689833786820190815203019020916001600160401b038211610720576106148261060e855461174f565b8561179d565b5f90601f8311600114610693579180610666927fd8c9334b1a9c2f9da342a0a2b32629c1a229b6445dad78947f674b44444a75509695945f92610688575b50508160011b915f199060031b1c19161790565b90555b61067381856117e2565b9361068360405192839283611816565b0390a3005b013590505f80610652565b601f198316916106a6855f5260205f2090565b925f5b81811061070857509160019391857fd8c9334b1a9c2f9da342a0a2b32629c1a229b6445dad78947f674b44444a755098979694106106ef575b505050811b019055610669565b01355f19600384901b60f8161c191690555f80806106e2565b919360206001819287870135815501950192016106a9565b610d57565b346101d05760403660031901126101d057602061074c6004356107466101d4565b90611893565b6040516001600160a01b039091168152f35b805180835260209291819084018484015e5f828201840152601f01601f1916010190565b90604061079a92603c8152816020820152019061075e565b90565b60409061079a93928152816020820152019061075e565b346101d05760403660031901126101d0576107d3602435600435611ab3565b906102336040519283928361079d565b346101d05760603660031901126101d05760043560243560443561080683611d72565b156101d0577f1d6f5e03d3f63eb58751986629a5439baee5079ff04f345becb66e23eb154e469160405161083981610d6b565b818152600160208201848152865f52600960205260405f2092518355519101556108756040519283928360209093929193604081019481520152565b0390a2005b346101d057610888366103b2565b610893839293611d72565b156101d057815f52600260205260405f20926001600160401b038211610720576108c7826108c1865461174f565b8661179d565b5f93601f83116001146109335761091683807fe379c1624ed7e714cc0937528a32359d69d5281337765313dba4e081b72d757896975f91610928575b508160011b915f199060031b1c19161790565b90555b61087560405192839283611816565b90508401355f610903565b601f19831694610946825f5260205f2090565b905f5b8781106109a35750847fe379c1624ed7e714cc0937528a32359d69d5281337765313dba4e081b72d757896971061098a575b5050600183811b019055610919565b8301355f19600386901b60f8161c191690555f8061097b565b90916020600181928588013581550193019101610949565b346101d05760203660031901126101d057602061074c600435611b2c565b346101d05760403660031901126101d0576004356024355f9182526006602090815260408084206004835281852054855282528084209284529181529181902054905161ffff90911615158152f35b90602061079a92818152019061075e565b346101d057610233610a7c610a836020610a52366103b2565b92915f52600a825260405f2083604051948593843782019081520301902060405192838092611a32565b0382610d86565b60405191829160208352602083019061075e565b346101d05760203660031901126101d0576004355f526003602052610233610a7c610a8360405f2060405192838092611a32565b346101d05760603660031901126101d0576004356024356044356001600160401b0381116101d057610b01903690600401610385565b610b0c849294611d72565b156101d0575f198301838111610c1b5783166101d057815f525f60205260405f20835f5260205260405f20906001600160401b03811161072057610b5a81610b54845461174f565b8461179d565b5f601f8211600114610bb2578190610b89939495965f926106885750508160011b915f199060031b1c19161790565b90555b7faa121bbeef5f32f5961a2a28966e769023910fc9479059ee3495d4c1a696efe35f80a3005b601f19821695610bc5845f5260205f2090565b915f5b888110610c0357508360019596979810610bea575b505050811b019055610b8c565b01355f19600384901b60f8161c191690555f8080610bdd565b90926020600181928686013581550194019101610bc8565b61170f565b346101d05760203660031901126101d0576004355f526008602052610233610a7c610a8360405f2060405192838092611a32565b346101d057610c62366103b2565b610c6d839293611d72565b156101d057815f52600860205260405f20926001600160401b03821161072057610c9b826108c1865461174f565b5f93601f8311600114610ce95761091683807fb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f796975f9161092857508160011b915f199060031b1c19161790565b601f19831694610cfc825f5260205f2090565b905f5b878110610d3f5750847fb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f796971061098a575050600183811b019055610919565b90916020600181928588013581550193019101610cff565b634e487b7160e01b5f52604160045260245ffd5b604081019081106001600160401b0382111761072057604052565b90601f801991011681019081106001600160401b0382111761072057604052565b6001600160401b03811161072057601f01601f191660200190565b929192610dce82610da7565b91610ddc6040519384610d86565b8294818452818301116101d0578281602093845f960137010152565b346101d05760603660031901126101d0576004356024356044356001600160401b0381116101d057366023820112156101d057610e3f903690602481600401359101610dc2565b91610e4981611d72565b156101d057807f65412581168e88a1e60c6459d7f44ae83ad0832e670826c05a4e2476b57af75260405180610e7f87878361079d565b0390a2603c8214610f5f575b5f52600160205260405f20905f5260205260405f2081516001600160401b03811161072057610ebe81610b54845461174f565b602092601f8211600114610efc57610eed929382915f92610ef15750508160011b915f199060031b1c19161790565b9055005b015190505f80610652565b601f19821693610f0f845f5260205f2090565b915f5b868110610f475750836001959610610f2f575b505050811b019055005b01515f1960f88460031b161c191690555f8080610f25565b91926020600181928685015181550194019201610f12565b807f52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd26020610f8c8661231b565b6040516001600160a01b039091168152a2610e8b565b6001600160a01b038116036101d057565b346101d05760403660031901126101d057600435610fd081610fa2565b60243580151581036101d0576001600160a01b0382169133831461106457335f908152600d6020526040902061102e91839161101d91905b9060018060a01b03165f5260205260405f2090565b9060ff801983541691151516179055565b604051901515815233907f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31908060208101610683565b60405162461bcd60e51b815260206004820152602960248201527f455243313135353a2073657474696e6720617070726f76616c20737461747573604482015268103337b91039b2b63360b91b6064820152608490fd5b346101d05760603660031901126101d05760043560443560243561ffff821682036101d05761112c610a7c926111389285610233965f52600560205260405f20905f52600460205260405f20545f5260205260405f20905f5260205260405f209061ffff165f5260205260405f2090565b60405192838092611a32565b60405191829182610a28565b602081016020825282518091526040820191602060408360051b8301019401925f915b83831061117657505050505090565b9091929394602080611194600193603f19868203018752895161075e565b97019301930191939290611167565b346101d05760203660031901126101d0576004356001600160401b0381116101d057366023820112156101d0578060040135906001600160401b0382116101d0573660248360051b830101116101d0576102339160246112039201611c89565b60405191829182611144565b346101d05760203660031901126101d05760043561122c81611d72565b156101d057805f52600460205260405f2080545f198114610c1b5760010190557fb757169b8492ca2f1c6619d9d76ce22803035c3b1d5f6930dffe7b127c1a19835f80a2005b346101d05760203660031901126101d0576004355f526002602052610233610a7c610a8360405f2060405192838092611a32565b346101d05760203660031901126101d0576004355f908152600960209081526040918290208054600190910154835191825291810191909152f35b346101d0576112ef366103b2565b91906112fa82611d72565b156101d057815f526003602052610a7c61131d60405f2060405192838092611a32565b825f52600360205260405f206001600160401b0385116107205761134b85611345835461174f565b8361179d565b5f601f86116001146113b757946108759161139d82807f8f15ed4b723ef428f250961da8315675b507046737e19319fc1a4d81bfe87f8598995f916113ac57508160011b915f199060031b1c19161790565b90555b60405193849384611d2d565b90508701355f610903565b601f198616906113ca835f5260205f2090565b915f5b81811061142e5750916108759391887f8f15ed4b723ef428f250961da8315675b507046737e19319fc1a4d81bfe87f8598999410611415575b5050600182811b0190556113a0565b8601355f19600385901b60f8161c191690555f80611406565b9192602060018192868a0135815501940192016113cd565b346101d05760403660031901126101d05760243560043561146682610fa2565b61146f81611d72565b156101d05761147c61232e565b9160601b602083015261148e81611d72565b156101d057807f65412581168e88a1e60c6459d7f44ae83ad0832e670826c05a4e2476b57af752604051806114c38682610782565b0390a2807f52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd260206114f38561231b565b6040516001600160a01b039091168152a25f52600160205260405f20603c5f5260205260405f2081516001600160401b0381116107205761153881610b54845461174f565b602092601f821160011461156757610eed929382915f92610ef15750508160011b915f199060031b1c19161790565b601f1982169361157a845f5260205f2090565b915f5b8681106115995750836001959610610f2f57505050811b019055005b9192602060018192868501518155019401920161157d565b346101d05760603660031901126101d0576004356115cd6101d4565b90604435916115db83610fa2565b6115e482611d72565b156101d05760207f7c69f06bea0bdef565b709e93a147836b0063ba2dd89f02d0b7e8d931e6a6daa91835f52600782526116328160405f209063ffffffff60e01b165f5260205260405f2090565b80546001600160a01b0319166001600160a01b0390961695861790556040519485526001600160e01b03191693a3005b346101d05760403660031901126101d057602060ff6116ba60043561168681610fa2565b6024359061169382610fa2565b60018060a01b03165f52600d845260405f209060018060a01b03165f5260205260405f2090565b54166040519015158152f35b346101d05760403660031901126101d057600435602435905f52600160205260405f20905f52602052610233610a7c610a8360405f2060405192838092611a32565b156101d057565b634e487b7160e01b5f52601160045260245ffd5b91908203918211610c1b57565b805191908290602001825e015f815290565b908092918237015f815290565b90600182811c9216801561177d575b602083101461176957565b634e487b7160e01b5f52602260045260245ffd5b91607f169161175e565b818110611792575050565b5f8155600101611787565b9190601f81116117ac57505050565b6117d6925f5260205f20906020601f840160051c830193106117d8575b601f0160051c0190611787565b565b90915081906117c9565b81604051928392833781015f815203902090565b908060209392818452848401375f828201840152601f01601f1916010190565b91602061079a9381815201916117f6565b60405190611836602083610d86565b5f8252565b3d15611865573d9061184c82610da7565b9161185a6040519384610d86565b82523d5f602084013e565b606090565b634e487b7160e01b5f52603260045260245ffd5b8051601f101561188e57603f0190565b61186a565b6118cf6118c2836118ac845f52600760205260405f2090565b9063ffffffff60e01b165f5260205260405f2090565b546001600160a01b031690565b6001600160a01b038116611a2257506118ea6118f691611b2c565b6001600160a01b031690565b906001600160a01b038216156119ef576040516301ffc9a760e01b6020820181815260248301919091525f918291906119328160448101610478565b5190855afa61193f61183b565b9015908115611a15575b81156119f5575b506119ef576040516301ffc9a760e01b602082019081526001600160e01b031990921660248201525f9182916119898160448101610478565b5190845afa61199661183b565b90159081156119e2575b81156119b4575b506119af5790565b505f90565b6001600160f81b031991506119da906119cc9061187e565b516001600160f81b03191690565b16155f6119a7565b90506020815110906119a0565b50505f90565b6001600160f81b03199150611a0d906119cc9061187e565b16155f611950565b9050602081511090611949565b91505090565b61079a905461174f565b5f9291815491611a418361174f565b8083529260018116908115611a965750600114611a5d57505050565b5f9081526020812093945091925b838310611a7c575060209250010190565b600181602092949394548385870101520191019190611a6b565b915050602093945060ff929192191683830152151560051b010190565b9190915f525f60205260405f2060015b83811115611adb5750509050611ad7611827565b5f91565b838116151580611b10575b611af25760011b611ac3565b8093505f52602052610a7c61079a60405f2060405192838092611a32565b50805f5281602052611b2560405f205461174f565b1515611ae6565b5f52600160205260405f20603c5f52602052610a7c611b5460405f2060405192838092611a32565b8051156119af5761079a9061231b565b91909182516001600160401b03811161072057611b8581610b54845461174f565b6020601f8211600114611bb8578190611bb49394955f92610ef15750508160011b915f199060031b1c19161790565b9055565b601f19821690611bcb845f5260205f2090565b915f5b818110611c0557509583600195969710611bed575b505050811b019055565b01515f1960f88460031b161c191690555f8080611be3565b9192602060018192868b015181550194019201611bce565b6001600160401b0381116107205760051b60200190565b919081101561188e5760051b81013590601e19813603018212156101d05701908135916001600160401b0383116101d05760200182360381136101d0579190565b805182101561188e5760209160051b010190565b611c9282611c1d565b91611ca06040519384610d86565b808352601f19611caf82611c1d565b015f5b818110611d1c5750505f5b818110611cca5750505090565b805f80611cda6001948688611c34565b90611cea60405180938193611742565b0390305af4611d00611cfa61183b565b91611708565b611d0a8287611c75565b52611d158186611c75565b5001611cbd565b806060602080938801015201611cb2565b91611d4461079a949260408552604085019061075e565b9260208185039101526117f6565b908160209103126101d0575161079a81610fa2565b6040513d5f823e3d90fd5b600b54611d87906001600160a01b03166118ea565b6040516302571be360e01b8152600481018390529190602090839060249082905afa918215611e9a575f92611e9f575b50600c548290611dcf906001600160a01b03166118ea565b906001600160a01b0382166001600160a01b0390911614611e31575b50506001600160a01b0381163314908115611e04575090565b6001600160a01b03165f908152600d6020526040902061079a9150611e2a903390611008565b5460ff1690565b6040516331a9108f60e11b81526004810192909252909150602090829060249082905afa908115611e9a575f91611e6b575b505f80611deb565b611e8d915060203d602011611e93575b611e858183610d86565b810190611d52565b5f611e63565b503d611e7b565b611d67565b611eb991925060203d602011611e9357611e858183610d86565b905f611db7565b9060405160e08101908082106001600160401b03831117610720576117d6916040525f60208201525f60408201525f60608201525f60808201525f60a0820152809381525f60c0820152611f38565b9060028201809211610c1b57565b9060048201809211610c1b57565b91908201809211610c1b57565b60c081019081519081602082015280518051831015611ff05782611f5b91612382565b8201809211610c1b5760a0611fca611faa611f9185611f8c611f81611fec9888516123d9565b61ffff166040880152565b611f0f565b611f8c611f9f8287516123d9565b61ffff166060870152565b611fc5611fb88286516123f7565b63ffffffff166080860152565b611f1d565b91611fe2611fdc6104bf8584516123d9565b93611f0f565b9182910152611f2b565b9052565b50505050565b61079a906020815191015161200b8183612382565b91612417565b908151815181149283612025575b50505090565b61203b9293508161203591612493565b92612493565b145f808061201f565b61ffff1661ffff8114610c1b5760010190565b61ffff61207061079a959360608452606084019061075e565b93166020820152604081840391015261075e565b61ffff168015610c1b575f190190565b61209e815461174f565b90816120a8575050565b81601f5f93116001146120b9575055565b818352602083206120d591601f0160051c810190600101611787565b808252602082209081548360011b9084198560031b1c191617905555565b9061ffff61210e60209295949560408552604085019061075e565b9416910152565b6121418197929496959395612132835f52600460205260405f2090565b54948651602088012098612417565b911561223b576121da91506121ab8661219e858481846121c16121bc8d7f03528ed0c2a3ebc993b12ce3c16bb382f9c7d88ef7d8a1bf290eaf35955a12079f6121ab9061219e6121df9f61219e859f5f52600560205260405f2090565b905f5260205260405f2090565b9061ffff165f5260205260405f2090565b611a28565b6121f3575b505061219e905f52600560205260405f2090565b612094565b6121ee604051928392836120f3565b0390a2565b61219e61220f9261219e612233955f52600660205260405f2090565b61222361221e825461ffff1690565b612084565b61ffff1661ffff19825416179055565b8a81846121c6565b816122aa866121ab8961219e8861219e886122977f52a608b3303a48862d07a73d82fa221318c0027fbbcfb1b2329bface3f19ff2b9f886121ab6121ee9f9261219e6122af9f9461219e6121bc965f52600560205260405f2090565b156122bb575f52600560205260405f2090565b611b64565b60405193849384612057565b6122ec6122d88661219e8661219e865f52600660205260405f2090565b6122236122e7825461ffff1690565b612044565b5f52600560205260405f2090565b80519060c060a082015191015190808203918211610c1b5761079a92612417565b60148151036101d0576020015160601c90565b6040805190919061233f8382610d86565b6014815291601f1901366020840137565b9061235a82610da7565b6123676040519182610d86565b8281528092612378601f1991610da7565b0190602036910137565b81905b80518310156123c557805183101561188e576020838201015160f81c9260018401808511610c1b578101809111610c1b5792612385575061079a91611723565b634e487b7160e01b5f52600160045260245ffd5b60028201808311610c1b578151106101d057016002015161ffff1690565b60048201808311610c1b578151106101d057016004015163ffffffff1690565b90828101808211610c1b578251106101d05760209061243584612350565b9392010160208301915b6020811015612463575f19906020036101000a019081199051169082511617905290565b90918251815260208101809111610c1b579160208101809111610c1b5790601f1981019081111561243f5761170f565b805182116101d057602001209056fea2646970667358221220d30fd8dfb138ad46feae6d06db38e227664de28eb7d99f86917118387d46f23b64736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000008a788f1daa51b1a31bee0de197d06b7c084f89610000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _ens (address): 0x8a788F1daA51B1a31bEe0dE197D06b7C084F8961
Arg [1] : wrapperAddress (address): 0x0000000000000000000000000000000000000000
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000008a788f1daa51b1a31bee0de197d06b7c084f8961
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.