Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
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 Name:
ConfigResolver
Compiler Version
v0.8.30+commit.73712a01
Optimization Enabled:
No with 200 runs
Other Settings:
prague EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: MIT
pragma solidity >=0.8.17 <0.9.0;
import "@ensdomains/ens-contracts/registry/ENS.sol";
import "@ensdomains/ens-contracts/resolvers/profiles/ABIResolver.sol";
import "@ensdomains/ens-contracts/resolvers/profiles/AddrResolver.sol";
import "@ensdomains/ens-contracts/resolvers/profiles/ContentHashResolver.sol";
import "@ensdomains/ens-contracts/resolvers/profiles/DNSResolver.sol";
import "@ensdomains/ens-contracts/resolvers/profiles/InterfaceResolver.sol";
import "@ensdomains/ens-contracts/resolvers/profiles/NameResolver.sol";
import "@ensdomains/ens-contracts/resolvers/profiles/PubkeyResolver.sol";
import "@ensdomains/ens-contracts/resolvers/profiles/TextResolver.sol";
import "@ensdomains/ens-contracts/resolvers/Multicallable.sol";
import {ReverseClaimer} from "@ensdomains/ens-contracts/reverseRegistrar/ReverseClaimer.sol";
import {INameWrapper} from "@ensdomains/ens-contracts/wrapper/INameWrapper.sol";
import {NameCoder} from "@ensdomains/ens-contracts/utils/NameCoder.sol";
bytes32 constant ADDR_REVERSE_NODE = 0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2;
bytes32 constant lookup = 0x3031323334353637383961626364656600000000000000000000000000000000;
/// A simple resolver anyone can use; only allows the owner of a node to set its
/// address.
contract ConfigResolver is
Multicallable,
ABIResolver,
AddrResolver,
ContentHashResolver,
DNSResolver,
InterfaceResolver,
NameResolver,
PubkeyResolver,
TextResolver,
ReverseClaimer
{
ENS immutable ens;
INameWrapper immutable 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;
/// A mapping of delegates. A delegate that is authorised by an owner
/// for a name may make changes to the name's resolver, but may not update
/// the set of token approvals.
/// (owner, name, delegate) => approved
mapping(address => mapping(bytes32 => mapping(address => bool))) private _tokenApprovals;
// Logged when an operator is added or removed.
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
// Logged when a delegate is approved or an approval is revoked.
event Approved(address owner, bytes32 indexed node, address indexed delegate, bool indexed approved);
constructor(ENS _ens, INameWrapper wrapperAddress) ReverseClaimer(_ens, msg.sender) {
ens = _ens;
nameWrapper = wrapperAddress;
}
/// @dev Returns the node hash for a given account's reverse records.
/// @param addr The address to hash
/// @return The ENS node hash.
function reverseNode(address addr) public pure returns (bytes32) {
bytes32 sha3HexAddress;
// An optimised function to compute the sha3 of the lower-case
// hexadecimal representation of an Ethereum address.
assembly {
for {
let i := 40
} gt(i, 0) {} {
i := sub(i, 1)
mstore8(i, byte(and(addr, 0xf), lookup))
addr := div(addr, 0x10)
i := sub(i, 1)
mstore8(i, byte(and(addr, 0xf), lookup))
addr := div(addr, 0x10)
}
sha3HexAddress := keccak256(0, 40)
}
return keccak256(abi.encodePacked(ADDR_REVERSE_NODE, sha3HexAddress));
}
/// @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);
}
/// @dev See {IERC1155-isApprovedForAll}.
function isApprovedForAll(address account, address operator) public view returns (bool) {
return _operatorApprovals[account][operator];
}
/// @dev Approve a delegate to be able to updated records on a node.
function approve(bytes32 node, address delegate, bool approved) external {
require(msg.sender != delegate, "Setting delegate status for self");
_tokenApprovals[msg.sender][node][delegate] = approved;
emit Approved(msg.sender, node, delegate, approved);
}
/// @dev Check to see if the delegate has been approved by the owner for the node.
function isApprovedFor(address owner, bytes32 node, address delegate) public view returns (bool) {
return _tokenApprovals[owner][node][delegate];
}
function isAuthorised(bytes32 node) internal view override returns (bool) {
if (reverseNode(msg.sender) == node) {
return true;
}
address owner = ens.owner(node);
if (owner == address(nameWrapper)) {
owner = nameWrapper.ownerOf(uint256(node));
}
return owner == msg.sender || isApprovedForAll(owner, msg.sender) || isApprovedFor(owner, node, msg.sender);
}
function supportsInterface(bytes4 interfaceID)
public
view
override(
Multicallable,
ABIResolver,
AddrResolver,
ContentHashResolver,
DNSResolver,
InterfaceResolver,
NameResolver,
PubkeyResolver,
TextResolver
)
returns (bool)
{
return super.supportsInterface(interfaceID);
}
}//SPDX-License-Identifier: MIT
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;
function setSubnodeRecord(
bytes32 node,
bytes32 label,
address owner,
address resolver,
uint64 ttl
) external;
function setSubnodeOwner(
bytes32 node,
bytes32 label,
address owner
) external returns (bytes32);
function setResolver(bytes32 node, address resolver) external;
function setOwner(bytes32 node, address owner) external;
function setTTL(bytes32 node, uint64 ttl) external;
function setApprovalForAll(address operator, bool approved) external;
function owner(bytes32 node) external view returns (address);
function resolver(bytes32 node) external view returns (address);
function ttl(bytes32 node) external view returns (uint64);
function recordExists(bytes32 node) external view returns (bool);
function isApprovedForAll(
address owner,
address operator
) external 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(uint64 => mapping(bytes32 => mapping(uint256 => bytes))) versionable_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
) external virtual authorised(node) {
// Content types must be powers of 2
require(((contentType - 1) & contentType) == 0);
versionable_abis[recordVersions[node]][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
) external view virtual override returns (uint256, bytes memory) {
mapping(uint256 => bytes) storage abiset = versionable_abis[
recordVersions[node]
][node];
for (
uint256 contentType = 1;
contentType > 0 && contentType <= contentTypes;
contentType <<= 1
) {
if (
(contentType & contentTypes) != 0 &&
abiset[contentType].length > 0
) {
return (contentType, abiset[contentType]);
}
}
return (0, bytes(""));
}
function supportsInterface(
bytes4 interfaceID
) public view virtual override returns (bool) {
return
interfaceID == type(IABIResolver).interfaceId ||
super.supportsInterface(interfaceID);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
import {ResolverBase, IERC165} from "../ResolverBase.sol";
import {IAddrResolver} from "./IAddrResolver.sol";
import {IAddressResolver} from "./IAddressResolver.sol";
import {IHasAddressResolver} from "./IHasAddressResolver.sol";
import {ENSIP19, COIN_TYPE_ETH, COIN_TYPE_DEFAULT} from "../../utils/ENSIP19.sol";
abstract contract AddrResolver is
IAddrResolver,
IAddressResolver,
IHasAddressResolver,
ResolverBase
{
mapping(uint64 => mapping(bytes32 => mapping(uint256 => bytes))) versionable_addresses;
/// @notice The supplied address could not be converted to `address`.
/// @dev Error selector: `0x8d666f60`
error InvalidEVMAddress(bytes addressBytes);
/// @notice Set `addr(60)` of the associated ENS node.
/// `address(0)` is stored as `new bytes(20)`.
/// @param node The node to update.
/// @param _addr The address to set.
function setAddr(
bytes32 node,
address _addr
) external virtual authorised(node) {
setAddr(node, COIN_TYPE_ETH, abi.encodePacked(_addr));
}
/// @notice Get `addr(60)` as `address` of the associated ENS node.
/// @param node The node to query.
/// @return The associated address.
function addr(
bytes32 node
) public view virtual override returns (address payable) {
return payable(address(bytes20(addr(node, COIN_TYPE_ETH))));
}
/// @notice Set the address for coin type of the associated ENS node.
/// Reverts `InvalidEVMAddress` if coin type is EVM and not 0 or 20 bytes.
/// @param node The node to update.
/// @param coinType The coin type.
/// @param addressBytes The address to set.
function setAddr(
bytes32 node,
uint256 coinType,
bytes memory addressBytes
) public virtual authorised(node) {
if (
addressBytes.length != 0 &&
addressBytes.length != 20 &&
ENSIP19.isEVMCoinType(coinType)
) {
revert InvalidEVMAddress(addressBytes);
}
emit AddressChanged(node, coinType, addressBytes);
if (coinType == COIN_TYPE_ETH) {
emit AddrChanged(node, address(bytes20(addressBytes)));
}
versionable_addresses[recordVersions[node]][node][
coinType
] = addressBytes;
}
/// @notice Get the address for coin type of the associated ENS node.
/// If coin type is EVM and empty, defaults to `addr(COIN_TYPE_DEFAULT)`.
/// @param node The node to query.
/// @param coinType The coin type.
/// @return addressBytes The assocated address.
function addr(
bytes32 node,
uint256 coinType
) public view virtual override returns (bytes memory addressBytes) {
mapping(uint256 => bytes) storage addrs = versionable_addresses[
recordVersions[node]
][node];
addressBytes = addrs[coinType];
if (
addressBytes.length == 0 && ENSIP19.chainFromCoinType(coinType) > 0
) {
addressBytes = addrs[COIN_TYPE_DEFAULT];
}
}
/// @inheritdoc IHasAddressResolver
function hasAddr(
bytes32 node,
uint256 coinType
) external view returns (bool) {
return
versionable_addresses[recordVersions[node]][node][coinType].length >
0;
}
/// @inheritdoc IERC165
function supportsInterface(
bytes4 interfaceId
) public view virtual override returns (bool) {
return
type(IAddrResolver).interfaceId == interfaceId ||
type(IAddressResolver).interfaceId == interfaceId ||
type(IHasAddressResolver).interfaceId == interfaceId ||
super.supportsInterface(interfaceId);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
import "../ResolverBase.sol";
import "./IContentHashResolver.sol";
abstract contract ContentHashResolver is IContentHashResolver, ResolverBase {
mapping(uint64 => mapping(bytes32 => bytes)) versionable_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
) external virtual authorised(node) {
versionable_hashes[recordVersions[node]][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
) external view virtual override returns (bytes memory) {
return versionable_hashes[recordVersions[node]][node];
}
function supportsInterface(
bytes4 interfaceID
) public view virtual override 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(uint64 => mapping(bytes32 => bytes)) private versionable_zonehashes;
// The records themselves. Stored as binary RRSETs
// node => version => name => resource => data
mapping(uint64 => mapping(bytes32 => mapping(bytes32 => mapping(uint16 => bytes))))
private versionable_records;
// Count of number of entries for a given name. Required for DNS resolvers
// when resolving wildcards.
// node => version => name => number of records
mapping(uint64 => mapping(bytes32 => mapping(bytes32 => uint16)))
private versionable_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
) external virtual authorised(node) {
uint16 resource = 0;
uint256 offset = 0;
bytes memory name;
bytes memory value;
bytes32 nameHash;
uint64 version = recordVersions[node];
// 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,
version
);
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,
version
);
}
}
/// 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
) public view virtual override returns (bytes memory) {
return versionable_records[recordVersions[node]][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
) public view virtual returns (bool) {
return (versionable_nameEntriesCount[recordVersions[node]][node][
name
] != 0);
}
/// 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
) external virtual authorised(node) {
uint64 currentRecordVersion = recordVersions[node];
bytes memory oldhash = versionable_zonehashes[currentRecordVersion][
node
];
versionable_zonehashes[currentRecordVersion][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
) external view virtual override returns (bytes memory) {
return versionable_zonehashes[recordVersions[node]][node];
}
function supportsInterface(
bytes4 interfaceID
) public view virtual override 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,
uint64 version
) private {
bytes32 nameHash = keccak256(name);
bytes memory rrData = data.substring(offset, size);
if (deleteRecord) {
if (
versionable_records[version][node][nameHash][resource].length !=
0
) {
versionable_nameEntriesCount[version][node][nameHash]--;
}
delete (versionable_records[version][node][nameHash][resource]);
emit DNSRecordDeleted(node, name, resource);
} else {
if (
versionable_records[version][node][nameHash][resource].length ==
0
) {
versionable_nameEntriesCount[version][node][nameHash]++;
}
versionable_records[version][node][nameHash][resource] = rrData;
emit DNSRecordChanged(node, name, resource, rrData);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "../ResolverBase.sol";
import "./AddrResolver.sol";
import "./IInterfaceResolver.sol";
abstract contract InterfaceResolver is IInterfaceResolver, AddrResolver {
mapping(uint64 => mapping(bytes32 => mapping(bytes4 => address))) versionable_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
) external virtual authorised(node) {
versionable_interfaces[recordVersions[node]][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
) external view virtual override returns (address) {
address implementer = versionable_interfaces[recordVersions[node]][
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(IERC165).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
) public view virtual override 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(uint64 => mapping(bytes32 => string)) versionable_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
) external virtual authorised(node) {
versionable_names[recordVersions[node]][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
) external view virtual override returns (string memory) {
return versionable_names[recordVersions[node]][node];
}
function supportsInterface(
bytes4 interfaceID
) public view virtual override 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(uint64 => mapping(bytes32 => PublicKey)) versionable_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
) external virtual authorised(node) {
versionable_pubkeys[recordVersions[node]][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
) external view virtual override returns (bytes32 x, bytes32 y) {
uint64 currentRecordVersion = recordVersions[node];
return (
versionable_pubkeys[currentRecordVersion][node].x,
versionable_pubkeys[currentRecordVersion][node].y
);
}
function supportsInterface(
bytes4 interfaceID
) public view virtual override 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(uint64 => mapping(bytes32 => mapping(string => string))) versionable_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
) external virtual authorised(node) {
versionable_texts[recordVersions[node]][node][key] = value;
emit TextChanged(node, key, key, value);
}
/// 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 virtual override returns (string memory) {
return versionable_texts[recordVersions[node]][node][key];
}
function supportsInterface(
bytes4 interfaceID
) public view virtual override returns (bool) {
return
interfaceID == type(ITextResolver).interfaceId ||
super.supportsInterface(interfaceID);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "./IMulticallable.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
abstract contract Multicallable is IMulticallable, ERC165 {
function _multicall(
bytes32 nodehash,
bytes[] calldata data
) internal returns (bytes[] memory results) {
results = new bytes[](data.length);
for (uint256 i = 0; i < data.length; i++) {
if (nodehash != bytes32(0)) {
bytes32 txNamehash = bytes32(data[i][4:36]);
require(
txNamehash == nodehash,
"multicall: All records must have a matching namehash"
);
}
(bool success, bytes memory result) = address(this).delegatecall(
data[i]
);
require(success);
results[i] = result;
}
return results;
}
// This function provides an extra security check when called
// from priviledged contracts (such as EthRegistrarController)
// that can set records on behalf of the node owners
function multicallWithNodeCheck(
bytes32 nodehash,
bytes[] calldata data
) external returns (bytes[] memory results) {
return _multicall(nodehash, data);
}
function multicall(
bytes[] calldata data
) public override returns (bytes[] memory results) {
return _multicall(bytes32(0), data);
}
function supportsInterface(
bytes4 interfaceID
) public view virtual override returns (bool) {
return
interfaceID == type(IMulticallable).interfaceId ||
super.supportsInterface(interfaceID);
}
}//SPDX-License-Identifier: MIT
pragma solidity >=0.8.17 <0.9.0;
import {ENS} from "../registry/ENS.sol";
import {IReverseRegistrar} from "../reverseRegistrar/IReverseRegistrar.sol";
contract ReverseClaimer {
bytes32 constant ADDR_REVERSE_NODE =
0x91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e2;
constructor(ENS ens, address claimant) {
IReverseRegistrar reverseRegistrar = IReverseRegistrar(
ens.owner(ADDR_REVERSE_NODE)
);
reverseRegistrar.claim(claimant);
}
}//SPDX-License-Identifier: MIT
pragma solidity ~0.8.17;
import "../registry/ENS.sol";
import "../ethregistrar/IBaseRegistrar.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "./IMetadataService.sol";
import "./INameWrapperUpgrade.sol";
uint32 constant CANNOT_UNWRAP = 1;
uint32 constant CANNOT_BURN_FUSES = 2;
uint32 constant CANNOT_TRANSFER = 4;
uint32 constant CANNOT_SET_RESOLVER = 8;
uint32 constant CANNOT_SET_TTL = 16;
uint32 constant CANNOT_CREATE_SUBDOMAIN = 32;
uint32 constant CANNOT_APPROVE = 64;
//uint16 reserved for parent controlled fuses from bit 17 to bit 32
uint32 constant PARENT_CANNOT_CONTROL = 1 << 16;
uint32 constant IS_DOT_ETH = 1 << 17;
uint32 constant CAN_EXTEND_EXPIRY = 1 << 18;
uint32 constant CAN_DO_EVERYTHING = 0;
uint32 constant PARENT_CONTROLLED_FUSES = 0xFFFF0000;
// all fuses apart from IS_DOT_ETH
uint32 constant USER_SETTABLE_FUSES = 0xFFFDFFFF;
interface INameWrapper is IERC1155 {
event NameWrapped(
bytes32 indexed node,
bytes name,
address owner,
uint32 fuses,
uint64 expiry
);
event NameUnwrapped(bytes32 indexed node, address owner);
event FusesSet(bytes32 indexed node, uint32 fuses);
event ExpiryExtended(bytes32 indexed node, uint64 expiry);
function ens() external view returns (ENS);
function registrar() external view returns (IBaseRegistrar);
function metadataService() external view returns (IMetadataService);
function names(bytes32) external view returns (bytes memory);
function name() external view returns (string memory);
function upgradeContract() external view returns (INameWrapperUpgrade);
function supportsInterface(bytes4 interfaceID) external view returns (bool);
function wrap(
bytes calldata name,
address wrappedOwner,
address resolver
) external;
function wrapETH2LD(
string calldata label,
address wrappedOwner,
uint16 ownerControlledFuses,
address resolver
) external returns (uint64 expires);
function registerAndWrapETH2LD(
string calldata label,
address wrappedOwner,
uint256 duration,
address resolver,
uint16 ownerControlledFuses
) external returns (uint256 registrarExpiry);
function renew(
uint256 labelHash,
uint256 duration
) external returns (uint256 expires);
function unwrap(bytes32 node, bytes32 label, address owner) external;
function unwrapETH2LD(
bytes32 label,
address newRegistrant,
address newController
) external;
function upgrade(bytes calldata name, bytes calldata extraData) external;
function setFuses(
bytes32 node,
uint16 ownerControlledFuses
) external returns (uint32 newFuses);
function setChildFuses(
bytes32 parentNode,
bytes32 labelhash,
uint32 fuses,
uint64 expiry
) external;
function setSubnodeRecord(
bytes32 node,
string calldata label,
address owner,
address resolver,
uint64 ttl,
uint32 fuses,
uint64 expiry
) external returns (bytes32);
function setRecord(
bytes32 node,
address owner,
address resolver,
uint64 ttl
) external;
function setSubnodeOwner(
bytes32 node,
string calldata label,
address newOwner,
uint32 fuses,
uint64 expiry
) external returns (bytes32);
function extendExpiry(
bytes32 node,
bytes32 labelhash,
uint64 expiry
) external returns (uint64);
function canModifyName(
bytes32 node,
address addr
) external view returns (bool);
function setResolver(bytes32 node, address resolver) external;
function setTTL(bytes32 node, uint64 ttl) external;
function ownerOf(uint256 id) external view returns (address owner);
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId) external view returns (address);
function getData(
uint256 id
) external view returns (address, uint32, uint64);
function setMetadataService(IMetadataService _metadataService) external;
function uri(uint256 tokenId) external view returns (string memory);
function setUpgradeContract(INameWrapperUpgrade _upgradeAddress) external;
function allFusesBurned(
bytes32 node,
uint32 fuseMask
) external view returns (bool);
function isWrapped(bytes32) external view returns (bool);
function isWrapped(bytes32, bytes32) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import {LibMem} from "./LibMem/LibMem.sol";
import {BytesUtils} from "./BytesUtils.sol";
/// @dev Library for encoding/decoding names.
///
/// An ENS name is stop-separated labels, eg. "aaa.bb.c".
///
/// A DNS-encoded name is composed of byte length-prefixed labels with a terminator byte.
/// eg. "\x03aaa\x02bb\x01c\x00".
///
/// * maximum label length is 255 bytes.
/// * length = 0 is reserved for the terminator (root).
/// * `dns.length == 2 + ens.length` and the mapping is injective.
///
library NameCoder {
/// @dev The namehash of "eth".
bytes32 public constant ETH_NODE =
0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae;
/// @dev The label was empty.
/// Error selector: `0xbf9a2740`
error LabelIsEmpty();
/// @dev The label was more than 255 bytes.
/// Error selector: `0xdab6c73c`
error LabelIsTooLong(string label);
/// @dev The DNS-encoded name is malformed.
/// Error selector: `0xba4adc23`
error DNSDecodingFailed(bytes dns);
/// @dev A label of the ENS name has an invalid size.
/// Error selector: `0x9a4c3e3b`
error DNSEncodingFailed(string ens);
/// @dev The `name` did not end with `suffix`.
///
/// @param name The DNS-encoded name.
/// @param suffix The DNS-encoded suffix.
error NoSuffixMatch(bytes name, bytes suffix);
/// @dev Read the `size` of the label at `offset`.
/// If `size = 0`, it must be the end of `name` (no junk at end).
/// Reverts `DNSDecodingFailed`.
///
/// @param name The DNS-encoded name.
/// @param offset The offset into `name` to start reading.
///
/// @return size The size of the label in bytes.
/// @return nextOffset The offset into `name` of the next label.
function nextLabel(
bytes memory name,
uint256 offset
) internal pure returns (uint8 size, uint256 nextOffset) {
unchecked {
if (offset >= name.length) {
revert DNSDecodingFailed(name);
}
size = uint8(name[offset]);
nextOffset = offset + 1 + size;
if (
size > 0 ? nextOffset >= name.length : nextOffset != name.length
) {
revert DNSDecodingFailed(name);
}
}
}
/// @dev Find the offset of the label before `offset` in `name`.
/// * `prevOffset(name, 0)` reverts
/// * `prevOffset(name, name.length + 1)` reverts
/// * `prevOffset(name, name.length) = name.length - 1`
/// * `prevOffset(name, name.length - 1) = <tld>`
/// Reverts `DNSDecodingFailed`.
///
/// @param name The DNS-encoded name.
/// @param offset The offset into `name` to start reading backwards.
///
/// @return prevOffset The offset into `name` of the previous label.
function prevLabel(
bytes memory name,
uint256 offset
) internal pure returns (uint256 prevOffset) {
while (true) {
(, uint256 nextOffset) = nextLabel(name, prevOffset);
if (nextOffset == offset) break;
if (nextOffset > offset) {
revert DNSDecodingFailed(name);
}
prevOffset = nextOffset;
}
}
/// @dev Count number of labels in `name`.
/// * `countLabels("\x03eth\x00") = 1`
/// * `countLabels("\x00") = 0`
/// Reverts like `nextLabel()`.
///
/// @param name The DNS-encoded parent name.
/// @param offset The offset into `name` to start hashing.
///
/// @return count The number of labels.
function countLabels(
bytes memory name,
uint256 offset
) internal pure returns (uint256 count) {
uint8 size;
while (true) {
(size, offset) = nextLabel(name, offset);
if (size == 0) break;
++count;
}
}
/// @dev Compute the ENS labelhash of the label at `offset` and the offset for the next label.
/// Reverts `DNSDecodingFailed`.
///
/// @param name The DNS-encoded name.
/// @param offset The offset into `name` to start reading.
///
/// @return labelHash The resulting labelhash.
/// @return nextOffset The offset into `name` of the next label.
function readLabel(
bytes memory name,
uint256 offset
) internal pure returns (bytes32 labelHash, uint256 nextOffset) {
uint8 size;
(size, nextOffset) = nextLabel(name, offset);
if (size > 0) {
assembly {
labelHash := keccak256(add(add(name, offset), 33), size)
}
}
}
/// @dev Read label at offset from a DNS-encoded name and the offset for the next label.
/// * `readLabel("\x03abc\x00", 0) = ("abc", 4)`
/// * `readLabel("\x00", 0) = ("", 1)`
/// Reverts `DNSDecodingFailed`.
///
/// @param name The DNS-encoded name.
/// @param offset The offset into `name` to start reading.
///
/// @return label The label corresponding to `offset`.
/// @return nextOffset The offset into `name` of the next label.
function extractLabel(
bytes memory name,
uint256 offset
) internal pure returns (string memory label, uint256 nextOffset) {
uint8 size;
(size, nextOffset) = nextLabel(name, offset);
bytes memory v = new bytes(size);
unchecked {
LibMem.copy(LibMem.ptr(v), LibMem.ptr(name) + offset + 1, size);
}
label = string(v);
}
/// @dev Reads first label from a DNS-encoded name.
/// Reverts `DNSDecodingFailed`.
/// Reverts `LabelIsEmpty` if the label was empty.
///
/// @param name The DNS-encoded name.
///
/// @return The first label.
function firstLabel(
bytes memory name
) internal pure returns (string memory) {
(string memory label, ) = extractLabel(name, 0);
if (bytes(label).length == 0) {
revert LabelIsEmpty();
}
return label;
}
/// @dev Compute the namehash of `name[:offset]`.
/// Reverts `DNSDecodingFailed`.
///
/// @param name The DNS-encoded name.
/// @param offset The offset into `name` to start hashing.
///
/// @return hash The namehash of `name[:offset]`.
function namehash(
bytes memory name,
uint256 offset
) internal pure returns (bytes32 hash) {
(hash, offset) = readLabel(name, offset);
if (hash != bytes32(0)) {
hash = namehash(namehash(name, offset), hash);
}
}
/// @dev Compute a child namehash from a parent namehash and child labelhash.
///
/// @param parentNode The namehash of the parent.
/// @param labelHash The labelhash of the child.
///
/// @return node The namehash of the child.
function namehash(
bytes32 parentNode,
bytes32 labelHash
) internal pure returns (bytes32 node) {
// ~100 gas less than: keccak256(abi.encode(parentNode, labelHash))
assembly {
mstore(0, parentNode)
mstore(32, labelHash)
node := keccak256(0, 64)
}
}
/// @dev Convert DNS-encoded name to ENS name.
/// * `decode("\x00") = ""`
/// * `decode("\x03eth\x00") = "eth"`
/// * `decode("\x03aaa\x02bb\x01c\x00") = "aa.bb.c"`
/// * `decode("\x03a.b\x00")` reverts
/// Reverts like `nextLabel()`.
///
/// @param dns The DNS-encoded name to convert.
///
/// @return ens The equivalent ENS name.
function decode(
bytes memory dns
) internal pure returns (string memory ens) {
unchecked {
uint256 n = dns.length;
if (n == 1 && dns[0] == 0) return ""; // only valid answer is root
if (n < 3) revert DNSDecodingFailed(dns);
bytes memory v = new bytes(n - 2); // always 2-shorter
LibMem.copy(LibMem.ptr(v), LibMem.ptr(dns) + 1, n - 2); // shift by -1 byte
uint256 offset;
while (true) {
(uint8 size, uint256 nextOffset) = nextLabel(dns, offset);
if (size == 0) break;
if (BytesUtils.includes(v, offset, size, ".")) {
revert DNSDecodingFailed(dns); // malicious label
}
if (offset > 0) {
v[offset - 1] = ".";
}
offset = nextOffset;
}
return string(v);
}
}
/// @dev Convert ENS name to DNS-encoded name.
/// * `encode("aaa.bb.c") = "\x03aaa\x02bb\x01c\x00"`
/// * `encode("eth") = "\x03eth\x00"`
/// * `encode("") = "\x00"`
/// Reverts `DNSEncodingFailed`.
///
/// @param ens The ENS name to convert.
///
/// @return dns The corresponding DNS-encoded name, eg. `\x03aaa\x02bb\x01c\x00`.
function encode(
string memory ens
) internal pure returns (bytes memory dns) {
unchecked {
uint256 n = bytes(ens).length;
if (n == 0) return hex"00"; // root
dns = new bytes(n + 2); // always 2-longer
LibMem.copy(LibMem.ptr(dns) + 1, LibMem.ptr(bytes(ens)), n); // shift by +1 byte
uint256 start; // remember position to write length
uint256 size;
for (uint256 i; i < n; ++i) {
if (bytes(ens)[i] == ".") {
size = i - start;
if (size == 0 || size > 255) {
revert DNSEncodingFailed(ens);
}
dns[start] = bytes1(uint8(size));
start = i + 1;
}
}
size = n - start;
if (size == 0 || size > 255) {
revert DNSEncodingFailed(ens);
}
dns[start] = bytes1(uint8(size));
}
}
/// @dev Find the offset into `name` that namehashes to `nodeSuffix`.
///
/// @param name The DNS-encoded name to search.
/// @param nodeSuffix The namehash to match.
///
/// @return matched True if `name` ends with `nodeSuffix`.
/// @return node The namehash of `name[offset:]`.
/// @return prevOffset The offset into `name` of the label before `nodeSuffix`, or `matchOffset` if no match or no prior label.
/// @return matchOffset The offset into `name` that namehashes to the `nodeSuffix`, or 0 if no match.
function matchSuffix(
bytes memory name,
uint256 offset,
bytes32 nodeSuffix
)
internal
pure
returns (
bool matched,
bytes32 node,
uint256 prevOffset,
uint256 matchOffset
)
{
(bytes32 labelHash, uint256 next) = readLabel(name, offset);
if (labelHash != bytes32(0)) {
(matched, node, prevOffset, matchOffset) = matchSuffix(
name,
next,
nodeSuffix
);
if (node == nodeSuffix) {
matched = true;
prevOffset = offset;
matchOffset = next;
}
node = namehash(node, labelHash);
}
if (node == nodeSuffix) {
matched = true;
prevOffset = matchOffset = offset;
}
}
/// @dev Assert `label` is an encodable size.
///
/// @param label The label to check.
///
/// @return The size of the label.
function assertLabelSize(
string memory label
) internal pure returns (uint8) {
uint256 n = bytes(label).length;
if (n == 0) revert LabelIsEmpty();
if (n > 255) revert LabelIsTooLong(label);
return uint8(n);
}
/// @dev Prepend `label` to DNS-encoded `name`.
/// * `addLabel("\x03eth\x00", "test") = "\x04test\x03eth\x00"`
/// * `addLabel("\x00", "eth") = "\x03eth\x00"`
/// * `addLabel("", "abc") = "\x03abc"` invalid
/// * `addLabel("", "")` reverts
/// Assumes `name` is properly encoded.
/// Reverts like `assertLabelSize()`.
///
/// @param name The DNS-encoded parent name.
/// @param label The child label to prepend.
///
/// @return The DNS-encoded child name.
function addLabel(
bytes memory name,
string memory label
) internal pure returns (bytes memory) {
return abi.encodePacked(assertLabelSize(label), label, name);
}
/// @dev Transform `label` to DNS-encoded `{label}.eth`.
/// * `ethName("eth") = "\x04test\x03eth\x00"`
/// Behaves like `addLabel()`.
///
/// @param label The label to encode.
///
/// @return The DNS-encoded name.
function ethName(string memory label) internal pure returns (bytes memory) {
return addLabel("\x03eth\x00", label);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
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 "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "./profiles/IVersionableResolver.sol";
abstract contract ResolverBase is ERC165, IVersionableResolver {
mapping(bytes32 => uint64) public recordVersions;
function isAuthorised(bytes32 node) internal view virtual returns (bool);
modifier authorised(bytes32 node) {
require(isAuthorised(node));
_;
}
/// Increments the record version 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.
function clearRecords(bytes32 node) public virtual authorised(node) {
recordVersions[node]++;
emit VersionChanged(node, recordVersions[node]);
}
function supportsInterface(
bytes4 interfaceID
) public view virtual override returns (bool) {
return
interfaceID == type(IVersionableResolver).interfaceId ||
super.supportsInterface(interfaceID);
}
}// 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,
uint256 coinType,
bytes newAddress
);
function addr(
bytes32 node,
uint256 coinType
) external view returns (bytes memory);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
interface IHasAddressResolver {
/// @notice Determine if an addresss is stored for the coin type of the associated ENS node.
/// @param node The node to query.
/// @param coinType The coin type.
/// @return True if the associated address is not empty.
function hasAddr(
bytes32 node,
uint256 coinType
) external view returns (bool);
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {HexUtils} from "../utils/HexUtils.sol";
import {NameCoder} from "../utils/NameCoder.sol";
uint32 constant CHAIN_ID_ETH = 1;
uint256 constant COIN_TYPE_ETH = 60;
uint256 constant COIN_TYPE_DEFAULT = 1 << 31; // 0x8000_0000
string constant SLUG_ETH = "addr"; // <=> COIN_TYPE_ETH
string constant SLUG_DEFAULT = "default"; // <=> COIN_TYPE_DEFAULT
string constant TLD_REVERSE = "reverse";
/// @dev Library for generating reverse names according to ENSIP-19.
/// https://docs.ens.domains/ensip/19
library ENSIP19 {
/// @dev The supplied address was `0x`.
/// Error selector: `0x7138356f`
error EmptyAddress();
/// @dev Extract Chain ID from `coinType`.
/// @param coinType The coin type.
/// @return The Chain ID or 0 if non-EVM Chain.
function chainFromCoinType(
uint256 coinType
) internal pure returns (uint32) {
if (coinType == COIN_TYPE_ETH) return CHAIN_ID_ETH;
coinType ^= COIN_TYPE_DEFAULT;
return uint32(coinType < COIN_TYPE_DEFAULT ? coinType : 0);
}
/// @dev Determine if Coin Type is for an EVM address.
/// @param coinType The coin type.
/// @return True if coin type represents an EVM address.
function isEVMCoinType(uint256 coinType) internal pure returns (bool) {
return coinType == COIN_TYPE_DEFAULT || chainFromCoinType(coinType) > 0;
}
/// @dev Generate Reverse Name from Address + Coin Type.
/// Reverts `EmptyAddress` if `addressBytes` is `0x`.
/// @param addressBytes The input address.
/// @param coinType The coin type.
/// @return The ENS reverse name, eg. `1234abcd.addr.reverse`.
function reverseName(
bytes memory addressBytes,
uint256 coinType
) internal pure returns (string memory) {
if (addressBytes.length == 0) {
revert EmptyAddress();
}
return
string(
abi.encodePacked(
HexUtils.bytesToHex(addressBytes),
bytes1("."),
coinType == COIN_TYPE_ETH
? SLUG_ETH
: coinType == COIN_TYPE_DEFAULT
? SLUG_DEFAULT
: HexUtils.unpaddedUintToHex(coinType, true),
bytes1("."),
TLD_REVERSE
)
);
}
/// @dev Parse Reverse Name into Address + Coin Type.
/// Matches: `/^[0-9a-fA-F]+\.([0-9a-f]{1,64}|addr|default)\.reverse$/`.
/// Reverts `DNSDecodingFailed`.
/// @param name The DNS-encoded name.
/// @return addressBytes The address or empty if invalid.
/// @return coinType The coin type.
function parse(
bytes memory name
) internal pure returns (bytes memory addressBytes, uint256 coinType) {
(, uint256 offset) = NameCoder.readLabel(name, 0);
bool valid;
(addressBytes, valid) = HexUtils.hexToBytes(name, 1, offset);
if (!valid || addressBytes.length == 0) return ("", 0); // addressBytes not 1+ hex
(valid, coinType) = parseNamespace(name, offset);
if (!valid) return ("", 0); // invalid namespace
}
/// @dev Parse Reverse Namespace into Coin Type.
/// Matches: `/^([0-9a-f]{1,64}|addr|default)\.reverse$/`.
/// Reverts `DNSDecodingFailed`.
/// @param name The DNS-encoded name.
/// @param offset The offset to begin parsing.
/// @return valid True if a valid reverse namespace.
/// @return coinType The coin type.
function parseNamespace(
bytes memory name,
uint256 offset
) internal pure returns (bool valid, uint256 coinType) {
(bytes32 labelHash, uint256 offsetTLD) = NameCoder.readLabel(
name,
offset
);
if (labelHash == keccak256(bytes(SLUG_ETH))) {
coinType = COIN_TYPE_ETH;
} else if (labelHash == keccak256(bytes(SLUG_DEFAULT))) {
coinType = COIN_TYPE_DEFAULT;
} else if (labelHash == bytes32(0)) {
return (false, 0); // no slug
} else {
(bytes32 word, bool validHex) = HexUtils.hexStringToBytes32(
name,
1 + offset,
offsetTLD
);
if (!validHex) return (false, 0); // invalid coinType or too long
coinType = uint256(word);
}
(labelHash, offset) = NameCoder.readLabel(name, offsetTLD);
if (labelHash != keccak256(bytes(TLD_REVERSE))) return (false, 0); // invalid tld
(labelHash, ) = NameCoder.readLabel(name, offset);
if (labelHash != bytes32(0)) return (false, 0); // not tld
valid = true;
}
}// 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);
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../utils/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,
uint256 offset
) internal pure returns (uint256) {
uint256 idx = offset;
while (true) {
assert(idx < self.length);
uint256 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,
uint256 offset
) internal pure returns (bytes memory ret) {
uint256 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,
uint256 offset
) internal pure returns (uint256) {
uint256 count = 0;
while (true) {
assert(offset < self.length);
uint256 labelLen = self.readUint8(offset);
offset += labelLen + 1;
if (labelLen == 0) {
break;
}
count += 1;
}
return count;
}
uint256 constant RRSIG_TYPE = 0;
uint256 constant RRSIG_ALGORITHM = 2;
uint256 constant RRSIG_LABELS = 3;
uint256 constant RRSIG_TTL = 4;
uint256 constant RRSIG_EXPIRATION = 8;
uint256 constant RRSIG_INCEPTION = 12;
uint256 constant RRSIG_KEY_TAG = 16;
uint256 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;
uint256 offset;
uint16 dnstype;
uint16 class;
uint32 ttl;
uint256 rdataOffset;
uint256 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,
uint256 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
uint256 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
uint256 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
);
}
uint256 constant DNSKEY_FLAGS = 0;
uint256 constant DNSKEY_PROTOCOL = 2;
uint256 constant DNSKEY_ALGORITHM = 3;
uint256 constant DNSKEY_PUBKEY = 4;
struct DNSKEY {
uint16 flags;
uint8 protocol;
uint8 algorithm;
bytes publicKey;
}
function readDNSKEY(
bytes memory data,
uint256 offset,
uint256 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
);
}
uint256 constant DS_KEY_TAG = 0;
uint256 constant DS_ALGORITHM = 2;
uint256 constant DS_DIGEST_TYPE = 3;
uint256 constant DS_DIGEST = 4;
struct DS {
uint16 keytag;
uint8 algorithm;
uint8 digestType;
bytes digest;
}
function readDS(
bytes memory data,
uint256 offset,
uint256 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);
}
function isSubdomainOf(
bytes memory self,
bytes memory other
) internal pure returns (bool) {
uint256 off = 0;
uint256 counts = labelCount(self, 0);
uint256 othercounts = labelCount(other, 0);
while (counts > othercounts) {
off = progress(self, off);
counts--;
}
return self.equals(off, other, 0);
}
function compareNames(
bytes memory self,
bytes memory other
) internal pure returns (int256) {
if (self.equals(other)) {
return 0;
}
uint256 off;
uint256 otheroff;
uint256 prevoff;
uint256 otherprevoff;
uint256 counts = labelCount(self, 0);
uint256 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) {
unchecked {
return int32(i1) - int32(i2) >= 0;
}
}
function progress(
bytes memory body,
uint256 off
) internal pure returns (uint256) {
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");
uint256 ac1;
uint256 ac2;
for (uint256 i = 0; i < data.length + 31; i += 32) {
uint256 word;
assembly {
word := mload(add(add(data, 32), i))
}
if (i + 32 > data.length) {
uint256 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);
/// 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
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.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,
string value
);
/// 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);
function multicallWithNodeCheck(
bytes32,
bytes[] calldata data
) external returns (bytes[] memory results);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}pragma solidity >=0.8.4;
interface IReverseRegistrar {
function setDefaultResolver(address resolver) external;
function claim(address owner) external returns (bytes32);
function claimForAddr(
address addr,
address owner,
address resolver
) external returns (bytes32);
function claimWithResolver(
address owner,
address resolver
) external returns (bytes32);
function setName(string memory name) external returns (bytes32);
function setNameForAddr(
address addr,
address owner,
address resolver,
string memory name
) external returns (bytes32);
function node(address addr) external pure returns (bytes32);
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../registry/ENS.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
interface IBaseRegistrar is IERC721 {
event ControllerAdded(address indexed controller);
event ControllerRemoved(address indexed controller);
event NameMigrated(
uint256 indexed id,
address indexed owner,
uint256 expires
);
event NameRegistered(
uint256 indexed id,
address indexed owner,
uint256 expires
);
event NameRenewed(uint256 indexed id, uint256 expires);
// Authorises a controller, who can register and renew domains.
function addController(address controller) external;
// Revoke controller permission for an address.
function removeController(address controller) external;
// Set the resolver for the TLD this registrar manages.
function setResolver(address resolver) external;
// Returns the expiration timestamp of the specified label hash.
function nameExpires(uint256 id) external view returns (uint256);
// Returns true if the specified name is available for registration.
function available(uint256 id) external view returns (bool);
/// @dev Register a name.
function register(
uint256 id,
address owner,
uint256 duration
) external returns (uint256);
function renew(uint256 id, uint256 duration) external returns (uint256);
/// @dev Reclaim ownership of a name in ENS, if you own it in the registrar.
function reclaim(uint256 id, address owner) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/IERC1155.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
*/
interface IERC1155 is IERC165 {
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/**
* @dev Returns the amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) external view returns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(
address[] calldata accounts,
uint256[] calldata ids
) external view returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}//SPDX-License-Identifier: MIT
pragma solidity ~0.8.17;
interface IMetadataService {
function uri(uint256) external view returns (string memory);
}//SPDX-License-Identifier: MIT
pragma solidity ~0.8.17;
interface INameWrapperUpgrade {
function wrapFromUpgrade(
bytes calldata name,
address wrappedOwner,
uint32 fuses,
uint64 expiry,
address approved,
bytes calldata extraData
) external;
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
library LibMem {
/// @dev Copy `mem[src:src+len]` to `mem[dst:dst+len]`.
/// Equivalent to `mcopy()`.
///
/// @param src The source memory offset.
/// @param dst The destination memory offset.
/// @param len The number of bytes to copy.
function copy(uint256 dst, uint256 src, uint256 len) internal pure {
assembly ("memory-safe") {
// Copy word-length chunks while possible
// prettier-ignore
for {} gt(len, 31) {} {
mstore(dst, mload(src))
dst := add(dst, 32)
src := add(src, 32)
len := sub(len, 32)
}
// Copy remaining bytes
if len {
let mask := sub(shl(shl(3, sub(32, len)), 1), 1)
let wSrc := and(mload(src), not(mask))
let wDst := and(mload(dst), mask)
mstore(dst, or(wSrc, wDst))
}
}
}
/// @dev Convert bytes to a memory offset.
///
/// @param v The bytes to convert.
///
/// @return ret The corresponding memory offset.
function ptr(bytes memory v) internal pure returns (uint256 ret) {
assembly ("memory-safe") {
ret := add(v, 32)
}
}
/// @dev Read word at memory offset.
///
/// @param src The memory offset.
///
/// @return ret The read word.
function load(uint256 src) internal pure returns (uint256 ret) {
assembly ("memory-safe") {
ret := mload(src)
}
}
}//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {LibMem} from "./LibMem/LibMem.sol";
library BytesUtils {
/// @dev `offset` was beyond `length`.
/// Error selector: `0x8a3c1cfb`
error OffsetOutOfBoundsError(uint256 offset, uint256 length);
/// @dev Assert `end` is not beyond the length of `v`.
function _checkBound(bytes memory v, uint256 end) internal pure {
if (end > v.length) {
revert OffsetOutOfBoundsError(end, v.length);
}
}
/// @dev Compute `keccak256(v[off:off+len])`.
/// @param v The source bytes.
/// @param off The offset into the source.
/// @param len The number of bytes to hash.
/// @return ret The corresponding hash.
function keccak(
bytes memory v,
uint256 off,
uint256 len
) internal pure returns (bytes32 ret) {
_checkBound(v, off + len);
assembly ("memory-safe") {
ret := keccak256(add(add(v, 32), off), len)
}
}
/// @dev Lexicographically compare two byte strings.
/// @param vA The first bytes to compare.
/// @param vB The second bytes to compare.
/// @return Positive number if `A > B`, negative number if `A < B`, or zero if `A == B`.
function compare(
bytes memory vA,
bytes memory vB
) internal pure returns (int256) {
return compare(vA, 0, vA.length, vB, 0, vB.length);
}
/// @dev Lexicographically compare two byte ranges: `A = vA[offA:offA+lenA]` and `B = vB[offB:offB+lenB]`.
/// @param vA The first bytes.
/// @param offA The offset of the first bytes.
/// @param lenA The length of the first bytes.
/// @param vB The second bytes.
/// @param offB The offset of the second bytes.
/// @param lenB The length of the second bytes.
/// @return Positive number if `A > B`, negative number if `A < B`, or zero if `A == B`.
function compare(
bytes memory vA,
uint256 offA,
uint256 lenA,
bytes memory vB,
uint256 offB,
uint256 lenB
) internal pure returns (int256) {
_checkBound(vA, offA + lenA);
_checkBound(vB, offB + lenB);
unchecked {
uint256 ptrA = LibMem.ptr(vA) + offA;
uint256 ptrB = LibMem.ptr(vB) + offB;
uint256 shortest = lenA < lenB ? lenA : lenB;
for (uint256 i; i < shortest; i += 32) {
uint256 a = LibMem.load(ptrA + i);
uint256 b = LibMem.load(ptrB + i);
if (a != b) {
uint256 rest = shortest - i;
if (rest < 32) {
rest = (32 - rest) << 3; // bits to drop
a >>= rest; // shift out the
b >>= rest; // irrelevant bits
}
if (a < b) {
return -1;
} else if (a > b) {
return 1;
}
}
}
}
return int256(lenA) - int256(lenB);
}
/// @dev Determine if `a[offA:offA+len] == b[offB:offB+len]`.
/// @param vA The first bytes.
/// @param offA The offset into the first bytes.
/// @param vB The second bytes.
/// @param offB The offset into the second bytes.
/// @param len The number of bytes to compare.
/// @return True if the byte ranges are equal.
function equals(
bytes memory vA,
uint256 offA,
bytes memory vB,
uint256 offB,
uint256 len
) internal pure returns (bool) {
return keccak(vA, offA, len) == keccak(vB, offB, len);
}
/// @dev Determine if `a[offA:] == b[offB:]`.
/// @param vA The first bytes.
/// @param offA The offset into the first bytes.
/// @param vB The second bytes.
/// @param offB The offset into the second bytes.
/// @return True if the byte ranges are equal.
function equals(
bytes memory vA,
uint256 offA,
bytes memory vB,
uint256 offB
) internal pure returns (bool) {
_checkBound(vA, offA);
_checkBound(vB, offB);
unchecked {
return
keccak(vA, offA, vA.length - offA) ==
keccak(vB, offB, vB.length - offB);
}
}
/// @dev Determine if `a[offA:] == b`.
/// @param vA The first bytes.
/// @param offA The offset into the first bytes.
/// @param vB The second bytes.
/// @return True if the byte ranges are equal.
function equals(
bytes memory vA,
uint256 offA,
bytes memory vB
) internal pure returns (bool) {
return
vA.length == offA + vB.length &&
keccak(vA, offA, vB.length) == keccak256(vB);
}
/// @dev Determine if `a == b`.
/// @param vA The first bytes.
/// @param vB The second bytes.
/// @return True if the bytes are equal.
function equals(
bytes memory vA,
bytes memory vB
) internal pure returns (bool) {
return vA.length == vB.length && keccak256(vA) == keccak256(vB);
}
/// @dev Returns `uint8(v[off])`.
/// @param v The source bytes.
/// @param off The offset into the source.
/// @return The corresponding `uint8`.
function readUint8(
bytes memory v,
uint256 off
) internal pure returns (uint8) {
_checkBound(v, off + 1);
unchecked {
return uint8(v[off]);
}
}
/// @dev Returns `uint16(bytes2(v[off:off+2]))`.
/// @param v The source bytes.
/// @param off The offset into the source.
/// @return ret The corresponding `uint16`.
function readUint16(
bytes memory v,
uint256 off
) internal pure returns (uint16 ret) {
_checkBound(v, off + 2);
assembly ("memory-safe") {
ret := shr(240, mload(add(add(v, 32), off)))
}
}
/// @dev Returns `uint32(bytes4(v[off:off+4]))`.
/// @param v The source bytes.
/// @param off The offset into the source.
/// @return ret The corresponding `uint32`.
function readUint32(
bytes memory v,
uint256 off
) internal pure returns (uint32 ret) {
_checkBound(v, off + 4);
assembly ("memory-safe") {
ret := shr(224, mload(add(add(v, 32), off)))
}
}
/// @dev Returns `bytes20(v[off:off+20])`.
/// @param v The source bytes.
/// @param off The offset into the source.
/// @return ret The corresponding `bytes20`.
function readBytes20(
bytes memory v,
uint256 off
) internal pure returns (bytes20 ret) {
_checkBound(v, off + 20);
assembly ("memory-safe") {
ret := shl(96, mload(add(add(v, 20), off)))
}
}
/// @dev Returns `bytes32(v[off:off+32])`.
/// @param v The source bytes.
/// @param off The offset into the source.
/// @return ret The corresponding `bytes32`.
function readBytes32(
bytes memory v,
uint256 off
) internal pure returns (bytes32 ret) {
_checkBound(v, off + 32);
assembly ("memory-safe") {
ret := mload(add(add(v, 32), off))
}
}
/// @dev Returns `bytes32(bytesN(v[off:off+len]))`.
/// Accepts 0-32 bytes or reverts.
/// @param v The source bytes.
/// @param off The offset into the source.
/// @param len The number of bytes.
/// @return ret The corresponding N-bytes left-aligned in a `bytes32`.
function readBytesN(
bytes memory v,
uint256 off,
uint256 len
) internal pure returns (bytes32 ret) {
assert(len <= 32);
_checkBound(v, off + len);
assembly ("memory-safe") {
let mask := sub(shl(shl(3, sub(32, len)), 1), 1) // <(32-N)x00><NxFF>
ret := and(mload(add(add(v, 32), off)), not(mask))
}
}
/// @dev Copy `vSrc[offSrc:offSrc+len]` to `vDst[offDst:offDst:len]`.
/// @param vSrc The source bytes.
/// @param offSrc The offset into the source to begin the copy.
/// @param vDst The destination bytes.
/// @param offDst The offset into the destination to place the copy.
/// @param len The number of bytes to copy.
function copyBytes(
bytes memory vSrc,
uint256 offSrc,
bytes memory vDst,
uint256 offDst,
uint256 len
) internal pure {
_checkBound(vSrc, offSrc + len);
_checkBound(vDst, offDst + len);
unchecked {
LibMem.copy(
LibMem.ptr(vDst) + offDst,
LibMem.ptr(vSrc) + offSrc,
len
);
}
}
/// @dev Copies a substring into a new byte string.
/// @param vSrc The byte string to copy from.
/// @param off The offset to start copying at.
/// @param len The number of bytes to copy.
/// @return vDst The copied substring.
function substring(
bytes memory vSrc,
uint256 off,
uint256 len
) internal pure returns (bytes memory vDst) {
vDst = new bytes(len);
copyBytes(vSrc, off, vDst, 0, len);
}
/// @dev Find the first occurrence of `needle`.
/// @param v The bytes to search.
/// @param off The offset to start searching.
/// @param len The number of bytes to search.
/// @param needle The byte to search for.
/// @return The offset of `needle`, or `type(uint256).max` if not found.
function find(
bytes memory v,
uint256 off,
uint256 len,
bytes1 needle
) internal pure returns (uint256) {
for (uint256 end = off + len; off < end; off++) {
if (v[off] == needle) {
return off;
}
}
return type(uint256).max;
}
/// @dev Returns `true` if word contains a zero byte.
function hasZeroByte(uint256 word) internal pure returns (bool) {
unchecked {
return
((~word &
(word -
0x0101010101010101010101010101010101010101010101010101010101010101)) &
0x8080808080808080808080808080808080808080808080808080808080808080) !=
0;
}
}
/// @dev Efficiently check if `v[off:off+len]` contains `needle` byte.
/// @param v The source bytes.
/// @param off The offset into the source.
/// @param len The number of bytes to search.
/// @param needle The byte to search for.
/// @return found `true` if `needle` was found.
function includes(
bytes memory v,
uint256 off,
uint256 len,
bytes1 needle
) internal pure returns (bool found) {
_checkBound(v, off + len);
unchecked {
uint256 wide = uint8(needle);
wide |= wide << 8;
wide |= wide << 16;
wide |= wide << 32;
wide |= wide << 64;
wide |= wide << 128; // broadcast byte across word
off += LibMem.ptr(v);
len += off;
while (off < len) {
uint256 word = LibMem.load(off) ^ wide; // zero needle byte
off += 32;
if (hasZeroByte(word)) {
return
off <= len ||
hasZeroByte(
word | ((1 << ((off - len) << 3)) - 1) // recheck overflow by making it nonzero
);
}
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4;
interface IVersionableResolver {
event VersionChanged(bytes32 indexed node, uint64 newVersion);
function recordVersions(bytes32 node) external view returns (uint64);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
library HexUtils {
/// @dev Convert `hexString[off:end]` to `bytes32`.
/// Accepts 0-64 hex-chars.
/// Uses right alignment: `1` → `0000000000000000000000000000000000000000000000000000000000000001`.
/// @param hexString The string to parse.
/// @param off The index to start parsing.
/// @param end The (exclusive) index to stop parsing.
/// @return word The parsed bytes32.
/// @return valid True if the parse was successful.
function hexStringToBytes32(
bytes memory hexString,
uint256 off,
uint256 end
) internal pure returns (bytes32 word, bool valid) {
if (end < off) return ("", false); // invalid range
uint256 nibbles = end - off;
if (nibbles > 64 || end > hexString.length) {
return (bytes32(0), false); // too large or out of bounds
}
uint256 src;
assembly {
src := add(add(hexString, 32), off)
}
valid = unsafeBytes(src, 0, nibbles);
assembly {
let pad := sub(32, shr(1, add(nibbles, 1))) // number of bytes
word := shr(shl(3, pad), mload(0)) // right align
}
}
/// @dev Convert `hexString[off:end]` to `address`.
/// Accepts exactly 40 hex-chars.
/// @param hexString The string to parse.
/// @param off The index to start parsing.
/// @param end The (exclusive) index to stop parsing.
/// @return addr The parsed address.
/// @return valid True if the parse was successful.
function hexToAddress(
bytes memory hexString,
uint256 off,
uint256 end
) internal pure returns (address addr, bool valid) {
if (off + 40 != end) return (address(0), false); // wrong length
bytes32 word;
(word, valid) = hexStringToBytes32(hexString, off, end);
addr = address(uint160(uint256(word)));
}
/// @dev Convert `hexString[off:end]` to `bytes`.
/// Accepts 0+ hex-chars.
/// @param hexString The string to parse.
/// @param off The index to start parsing.
/// @param end The (exclusive) index to stop parsing.
/// @return v The parsed bytes.
/// @return valid True if the parse was successful.
function hexToBytes(
bytes memory hexString,
uint256 off,
uint256 end
) internal pure returns (bytes memory v, bool valid) {
if (end < off) return ("", false); // invalid range
uint256 nibbles = end - off;
v = new bytes((1 + nibbles) >> 1); // round up
uint256 src;
uint256 dst;
assembly {
src := add(add(hexString, 32), off)
dst := add(v, 32)
}
valid = unsafeBytes(src, dst, nibbles);
}
/// @dev Convert arbitrary hex-encoded memory to bytes.
/// If nibbles is odd, leading hex-char is padded, eg. `F` → `0x0F`.
/// Matches: `/^[0-9a-f]*$/i`.
/// @param src The memory offset of first hex-char of input.
/// @param dst The memory offset of first byte of output (cannot alias `src`).
/// @param nibbles The number of hex-chars to convert.
/// @return valid True if all characters were hex.
function unsafeBytes(
uint256 src,
uint256 dst,
uint256 nibbles
) internal pure returns (bool valid) {
assembly {
function getHex(c, i) -> ascii {
c := byte(i, c)
// chars 48-57: 0-9
if and(gt(c, 47), lt(c, 58)) {
ascii := sub(c, 48)
leave
}
// chars 65-70: A-F
if and(gt(c, 64), lt(c, 71)) {
ascii := add(sub(c, 65), 10)
leave
}
// chars 97-102: a-f
if and(gt(c, 96), lt(c, 103)) {
ascii := add(sub(c, 97), 10)
leave
}
// invalid char
ascii := 0x100
}
valid := true
let end := add(src, nibbles)
if and(nibbles, 1) {
let b := getHex(mload(src), 0) // "f" -> 15
mstore8(dst, b) // write ascii byte
src := add(src, 1) // update pointers
dst := add(dst, 1)
if gt(b, 255) {
valid := false
src := end // terminate loop
}
}
// prettier-ignore
for {} lt(src, end) {
src := add(src, 2) // 2 nibbles
dst := add(dst, 1) // per byte
} {
let word := mload(src) // read word (left aligned)
let b := or(shl(4, getHex(word, 0)), getHex(word, 1)) // "ff" -> 255
if gt(b, 255) {
valid := false
break
}
mstore8(dst, b) // write ascii byte
}
}
}
/// @dev Format `address` as a hex string.
/// @param addr The address to format.
/// @return hexString The corresponding hex string w/o a 0x-prefix.
function addressToHex(
address addr
) internal pure returns (string memory hexString) {
// return bytesToHex(abi.encodePacked(addr));
hexString = new string(40);
uint256 dst;
assembly {
mstore(0, addr)
dst := add(hexString, 32)
}
unsafeHex(12, dst, 40);
}
/// @dev Format `uint256` as a variable-length hex string without zero padding.
/// * unpaddedUintToHex(0, true) = "0"
/// * unpaddedUintToHex(1, true) = "1"
/// * unpaddedUintToHex(0, false) = "00"
/// * unpaddedUintToHex(1, false) = "01"
/// @param value The number to format.
/// @param dropZeroNibble If true, the leading byte will use one nibble if less than 16.
/// @return hexString The corresponding hex string w/o an 0x-prefix.
function unpaddedUintToHex(
uint256 value,
bool dropZeroNibble
) internal pure returns (string memory hexString) {
uint256 temp = value;
uint256 shift;
for (uint256 b = 128; b >= 8; b >>= 1) {
if (temp < (1 << b)) {
shift += b; // number of zero upper bits
} else {
temp >>= b; // shift away lower half
}
}
if (dropZeroNibble && temp < 16) shift += 4;
uint256 nibbles = 64 - (shift >> 2);
hexString = new string(nibbles);
uint256 dst;
assembly {
mstore(0, shl(shift, value)) // left-align
dst := add(hexString, 32)
}
unsafeHex(0, dst, nibbles);
}
/// @dev Format `bytes` as a hex string.
/// @param v The bytes to format.
/// @return hexString The corresponding hex string w/o a 0x-prefix.
function bytesToHex(
bytes memory v
) internal pure returns (string memory hexString) {
uint256 nibbles = v.length << 1;
hexString = new string(nibbles);
uint256 src;
uint256 dst;
assembly {
src := add(v, 32)
dst := add(hexString, 32)
}
unsafeHex(src, dst, nibbles);
}
/// @dev Converts arbitrary memory to a hex string.
/// @param src The memory offset of first nibble of input.
/// @param dst The memory offset of first hex-char of output (can alias `src`).
/// @param nibbles The number of nibbles to convert and the byte-length of the output.
function unsafeHex(
uint256 src,
uint256 dst,
uint256 nibbles
) internal pure {
unchecked {
for (uint256 end = dst + nibbles; dst < end; src += 32) {
uint256 word;
assembly {
word := mload(src)
}
for (uint256 shift = 256; dst < end && shift > 0; dst++) {
uint256 b = (word >> (shift -= 4)) & 15; // each nibble
b = b < 10 ? b + 0x30 : b + 0x57; // ("a" - 10) => 0x57
assembly {
mstore8(dst, b)
}
}
}
}
}
}// 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;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}{
"remappings": [
"forge-std/=node_modules/forge-std/src/",
"@ensdomains/ens-contracts/=node_modules/@ensdomains/ens-contracts/contracts/",
"@unruggable/gateways/=node_modules/@unruggable/gateways/contracts/",
"@openzeppelin/contracts-v5/=node_modules/@openzeppelin/contracts-v5/",
"@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/",
"clones-with-immutable-args/=node_modules/clones-with-immutable-args/",
"@ensdomains/buffer/contracts/Buffer.sol=node_modules/@ensdomains/buffer/contracts/Buffer.sol",
"hardhat/=node_modules/hardhat/"
],
"optimizer": {
"enabled": false,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": false
}Contract ABI
API[{"inputs":[{"internalType":"contract ENS","name":"_ens","type":"address"},{"internalType":"contract INameWrapper","name":"wrapperAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"bytes","name":"addressBytes","type":"bytes"}],"name":"InvalidEVMAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"length","type":"uint256"}],"name":"OffsetOutOfBoundsError","type":"error"},{"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":false,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":true,"internalType":"bool","name":"approved","type":"bool"}],"name":"Approved","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"},{"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"},{"indexed":false,"internalType":"string","name":"value","type":"string"}],"name":"TextChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"node","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"newVersion","type":"uint64"}],"name":"VersionChanged","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":"addressBytes","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"delegate","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"}],"name":"clearRecords","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":"uint256","name":"coinType","type":"uint256"}],"name":"hasAddr","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"owner","type":"address"},{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"delegate","type":"address"}],"name":"isApprovedFor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"nodehash","type":"bytes32"},{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicallWithNodeCheck","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":"","type":"bytes32"}],"name":"recordVersions","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"reverseNode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","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":"addressBytes","type":"bytes"}],"name":"setAddr","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"node","type":"bytes32"},{"internalType":"address","name":"_addr","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":"view","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
60c060405234801561000f575f5ffd5b5060405161577f38038061577f83398181016040528101906100319190610266565b81335f8273ffffffffffffffffffffffffffffffffffffffff166302571be37f91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e25f1b6040518263ffffffff1660e01b815260040161008f91906102bc565b602060405180830381865afa1580156100aa573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100ce91906102ff565b90508073ffffffffffffffffffffffffffffffffffffffff16631e83409a836040518263ffffffff1660e01b81526004016101099190610339565b6020604051808303815f875af1158015610125573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610149919061037c565b505050508173ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff1660a08173ffffffffffffffffffffffffffffffffffffffff168152505050506103a7565b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6101e9826101c0565b9050919050565b5f6101fa826101df565b9050919050565b61020a816101f0565b8114610214575f5ffd5b50565b5f8151905061022581610201565b92915050565b5f610235826101df565b9050919050565b6102458161022b565b811461024f575f5ffd5b50565b5f815190506102608161023c565b92915050565b5f5f6040838503121561027c5761027b6101bc565b5b5f61028985828601610217565b925050602061029a85828601610252565b9150509250929050565b5f819050919050565b6102b6816102a4565b82525050565b5f6020820190506102cf5f8301846102ad565b92915050565b6102de816101df565b81146102e8575f5ffd5b50565b5f815190506102f9816102d5565b92915050565b5f60208284031215610314576103136101bc565b5b5f610321848285016102eb565b91505092915050565b610333816101df565b82525050565b5f60208201905061034c5f83018461032a565b92915050565b61035b816102a4565b8114610365575f5ffd5b50565b5f8151905061037681610352565b92915050565b5f60208284031215610391576103906101bc565b5b5f61039e84828501610368565b91505092915050565b60805160a0516153b06103cf5f395f8181612709015261275c01525f61266f01526153b05ff3fe608060405234801561000f575f5ffd5b50600436106101ee575f3560e01c8063773722131161010d578063c8690233116100a0578063e32954eb1161006f578063e32954eb14610644578063e59d895d14610674578063e985e9c514610690578063f1cb7e06146106c0576101ee565b8063c8690233146105ab578063ce3decdc146105dc578063d5fa2b00146105f8578063d700ff3314610614576101ee565b8063a8fa5682116100dc578063a8fa5682146104eb578063a9784b3e1461051b578063ac9650d81461054b578063bc1c58d11461057b576101ee565b8063773722131461047b5780638b95dd7114610497578063a22cb465146104b3578063a4b91a01146104cf576101ee565b80633603d758116101855780635c98042b116101545780635c98042b146103cf578063623195b0146103ff578063691f34311461041b5780637315937d1461044b576101ee565b80633603d758146103235780633b3b57de1461033f5780634cbf6ba41461036f57806359d1d43c1461039f576101ee565b80632203ab56116101c15780632203ab561461028a57806329cd62ea146102bb578063304e6ade146102d757806332f111d7146102f3576101ee565b806301ffc9a7146101f25780630af179d71461022257806310f13a8c1461023e578063124a319c1461025a575b5f5ffd5b61020c6004803603810190610207919061391e565b6106f0565b6040516102199190613963565b60405180910390f35b61023c60048036038101906102379190613a10565b610701565b005b61025860048036038101906102539190613ac2565b610956565b005b610274600480360381019061026f9190613b53565b610a4b565b6040516102819190613bd0565b60405180910390f35b6102a4600480360381019061029f9190613c1c565b610e8c565b6040516102b2929190613cd9565b60405180910390f35b6102d560048036038101906102d09190613d07565b611005565b005b6102f160048036038101906102ec9190613a10565b6110d8565b005b61030d60048036038101906103089190613c1c565b611191565b60405161031a9190613963565b60405180910390f35b61033d60048036038101906103389190613d57565b61120f565b005b61035960048036038101906103549190613d57565b6112da565b6040516103669190613da2565b60405180910390f35b61038960048036038101906103849190613dbb565b6112f9565b6040516103969190613963565b60405180910390f35b6103b960048036038101906103b49190613df9565b61137d565b6040516103c69190613ea8565b60405180910390f35b6103e960048036038101906103e49190613d57565b611484565b6040516103f69190613ec8565b60405180910390f35b61041960048036038101906104149190613ee8565b61156b565b005b61043560048036038101906104309190613d57565b611641565b6040516104429190613ea8565b60405180910390f35b61046560048036038101906104609190613f83565b611728565b6040516104729190613fbd565b60405180910390f35b61049560048036038101906104909190613df9565b6117fc565b005b6104b160048036038101906104ac91906140fe565b6118b5565b005b6104cd60048036038101906104c89190614194565b611a2e565b005b6104e960048036038101906104e491906141d2565b611b94565b005b61050560048036038101906105009190614259565b611cf7565b6040516105129190613ec8565b60405180910390f35b610535600480360381019061053091906142a9565b611e06565b6040516105429190613963565b60405180910390f35b6105656004803603810190610560919061434e565b611ea4565b604051610572919061449c565b60405180910390f35b61059560048036038101906105909190613d57565b611ebb565b6040516105a29190613ec8565b60405180910390f35b6105c560048036038101906105c09190613d57565b611fa2565b6040516105d39291906144bc565b60405180910390f35b6105f660048036038101906105f19190613a10565b612044565b005b610612600480360381019061060d91906144e3565b6121c3565b005b61062e60048036038101906106299190613d57565b612205565b60405161063b9190614543565b60405180910390f35b61065e6004803603810190610659919061455c565b612228565b60405161066b919061449c565b60405180910390f35b61068e600480360381019061068991906145b9565b61223e565b005b6106aa60048036038101906106a59190614609565b612390565b6040516106b79190613963565b60405180910390f35b6106da60048036038101906106d59190613c1c565b61241e565b6040516106e79190613ec8565b60405180910390f35b5f6106fa826125da565b9050919050565b8261070b81612653565b610713575f5ffd5b5f5f90505f5f90506060805f5f5f5f8b81526020019081526020015f205f9054906101000a900467ffffffffffffffff1690505f61079d5f8b8b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505061285290919063ffffffff16565b90505b6107a98161287b565b6108db575f8761ffff160361080357806040015196506107c88161288f565b9450846040516020016107db9190614681565b6040516020818303038152906040528051906020012092506107fc816128c4565b93506108cd565b5f61080d8261288f565b9050816040015161ffff168861ffff1614158061083a575061083881876128fc90919063ffffffff16565b155b156108cb576108a48c878a8e8e8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f820116905080830192505050505050508b8c886020015161089a91906146c4565b5f8c51148a612923565b8160400151975081602001519650809550858051906020012093506108c8826128c4565b94505b505b6108d681612c73565b6107a0565b505f8451111561094a576109498a85888c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050898a8f8f905061093f91906146c4565b5f8a511488612923565b5b50505050505050505050565b8461096081612653565b610968575f5ffd5b8282600a5f5f5f8b81526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8981526020019081526020015f2087876040516109d1929190614725565b908152602001604051809103902091826109ec929190614944565b5084846040516109fd929190614725565b6040518091039020867f448bc014f1536726cf8d54ff3d6481ed3cbc683c2591ca204274009afa09b1a187878787604051610a3b9493929190614a3d565b60405180910390a3505050505050565b5f5f60075f5f5f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610b4f5780915050610e86565b5f610b59856112da565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610b98575f92505050610e86565b5f5f8273ffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000604051602401610be29190614a85565b6040516020818303038152906040527f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610c6c9190614681565b5f60405180830381855afa9150503d805f8114610ca4576040519150601f19603f3d011682016040523d82523d5f602084013e610ca9565b606091505b5091509150811580610cbc575060208151105b80610d0957505f60f81b81601f81518110610cda57610cd9614a9e565b5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b15610d1a575f945050505050610e86565b8273ffffffffffffffffffffffffffffffffffffffff1686604051602401610d429190614a85565b6040516020818303038152906040527f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610dcc9190614681565b5f60405180830381855afa9150503d805f8114610e04576040519150601f19603f3d011682016040523d82523d5f602084013e610e09565b606091505b508092508193505050811580610e20575060208151105b80610e6d57505f60f81b81601f81518110610e3e57610e3d614a9e565b5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b15610e7e575f945050505050610e86565b829450505050505b92915050565b5f60605f60015f5f5f8881526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f2090505f600190505b5f81118015610efe5750848111155b15610fe7575f85821614158015610f3057505f825f8381526020019081526020015f208054610f2c90614774565b9050115b15610fdb5780825f8381526020019081526020015f20808054610f5290614774565b80601f0160208091040260200160405190810160405280929190818152602001828054610f7e90614774565b8015610fc95780601f10610fa057610100808354040283529160200191610fc9565b820191905f5260205f20905b815481529060010190602001808311610fac57829003601f168201915b50505050509050935093505050610ffe565b600181901b9050610eef565b505f60405180602001604052805f81525092509250505b9250929050565b8261100f81612653565b611017575f5ffd5b60405180604001604052808481526020018381525060095f5f5f8881526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f205f820151815f015560208201518160010155905050837f1d6f5e03d3f63eb58751986629a5439baee5079ff04f345becb66e23eb154e4684846040516110ca9291906144bc565b60405180910390a250505050565b826110e281612653565b6110ea575f5ffd5b828260035f5f5f8981526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8781526020019081526020015f209182611150929190614b2d565b50837fe379c1624ed7e714cc0937528a32359d69d5281337765313dba4e081b72d75788484604051611183929190614c26565b60405180910390a250505050565b5f5f60025f5f5f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f8481526020019081526020015f20805461120490614774565b905011905092915050565b8061121981612653565b611221575f5ffd5b5f5f8381526020019081526020015f205f81819054906101000a900467ffffffffffffffff168092919061125490614c48565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555050817fc6621ccb8f3f5a04bb6502154b2caf6adf5983fe76dfef1cfc9c42e3579db4445f5f8581526020019081526020015f205f9054906101000a900467ffffffffffffffff166040516112ce9190614543565b60405180910390a25050565b5f6112e682603c61241e565b6112ef90614cc5565b60601c9050919050565b5f5f60065f5f5f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f8481526020019081526020015f205f9054906101000a900461ffff1661ffff161415905092915050565b6060600a5f5f5f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f2083836040516113e6929190614725565b908152602001604051809103902080546113ff90614774565b80601f016020809104026020016040519081016040528092919081815260200182805461142b90614774565b80156114765780601f1061144d57610100808354040283529160200191611476565b820191905f5260205f20905b81548152906001019060200180831161145957829003601f168201915b505050505090509392505050565b606060045f5f5f8581526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f2080546114e890614774565b80601f016020809104026020016040519081016040528092919081815260200182805461151490614774565b801561155f5780601f106115365761010080835404028352916020019161155f565b820191905f5260205f20905b81548152906001019060200180831161154257829003601f168201915b50505050509050919050565b8361157581612653565b61157d575f5ffd5b5f8460018661158c91906146c4565b1614611596575f5ffd5b828260015f5f5f8a81526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8881526020019081526020015f205f8781526020019081526020015f20918261160b929190614b2d565b5083857faa121bbeef5f32f5961a2a28966e769023910fc9479059ee3495d4c1a696efe360405160405180910390a35050505050565b606060085f5f5f8581526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f2080546116a590614774565b80601f01602080910402602001604051908101604052809291908181526020018280546116d190614774565b801561171c5780601f106116f35761010080835404028352916020019161171c565b820191905f5260205f20905b8154815290600101906020018083116116ff57829003601f168201915b50505050509050919050565b5f5f60285b5f8111156117a2576001810390507f3031323334353637383961626364656600000000000000000000000000000000600f85161a81536010840493506001810390507f3031323334353637383961626364656600000000000000000000000000000000600f85161a815360108404935061172d565b5060285f2090507f91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e25f1b816040516020016117de929190614d4b565b60405160208183030381529060405280519060200120915050919050565b8261180681612653565b61180e575f5ffd5b828260085f5f5f8981526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8781526020019081526020015f209182611874929190614944565b50837fb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f784846040516118a7929190614d76565b60405180910390a250505050565b826118bf81612653565b6118c7575f5ffd5b5f8251141580156118da57506014825114155b80156118eb57506118ea83612db1565b5b1561192d57816040517f8d666f600000000000000000000000000000000000000000000000000000000081526004016119249190613ec8565b60405180910390fd5b837f65412581168e88a1e60c6459d7f44ae83ad0832e670826c05a4e2476b57af752848460405161195f929190613cd9565b60405180910390a2603c83036119b457837f52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd28361199b90614cc5565b60601c6040516119ab9190613bd0565b60405180910390a25b8160025f5f5f8881526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f205f8581526020019081526020015f209081611a279190614d98565b5050505050565b8173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1603611a9c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a9390614ed7565b60405180910390fd5b80600b5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051611b889190613963565b60405180910390a35050565b8173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1603611c02576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bf990614f3f565b60405180910390fd5b80600c5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508015158273ffffffffffffffffffffffffffffffffffffffff16847ff0ddb3b04746704017f9aa8bd728fcc2c1d11675041205350018915f5e4750a033604051611cea9190613bd0565b60405180910390a4505050565b606060055f5f5f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f8481526020019081526020015f205f8361ffff1661ffff1681526020019081526020015f208054611d8190614774565b80601f0160208091040260200160405190810160405280929190818152602001828054611dad90614774565b8015611df85780601f10611dcf57610100808354040283529160200191611df8565b820191905f5260205f20905b815481529060010190602001808311611ddb57829003601f168201915b505050505090509392505050565b5f600c5f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8481526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff1690509392505050565b6060611eb35f5f1b8484612dd8565b905092915050565b606060035f5f5f8581526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f208054611f1f90614774565b80601f0160208091040260200160405190810160405280929190818152602001828054611f4b90614774565b8015611f965780601f10611f6d57610100808354040283529160200191611f96565b820191905f5260205f20905b815481529060010190602001808311611f7957829003601f168201915b50505050509050919050565b5f5f5f5f5f8581526020019081526020015f205f9054906101000a900467ffffffffffffffff16905060095f8267ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f015460095f8367ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f20600101549250925050915091565b8261204e81612653565b612056575f5ffd5b5f5f5f8681526020019081526020015f205f9054906101000a900467ffffffffffffffff1690505f60045f8367ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8781526020019081526020015f2080546120bd90614774565b80601f01602080910402602001604051908101604052809291908181526020018280546120e990614774565b80156121345780601f1061210b57610100808354040283529160200191612134565b820191905f5260205f20905b81548152906001019060200180831161211757829003601f168201915b50505050509050848460045f8567ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8981526020019081526020015f20918261217e929190614b2d565b50857f8f15ed4b723ef428f250961da8315675b507046737e19319fc1a4d81bfe87f858287876040516121b393929190614f5d565b60405180910390a2505050505050565b816121cd81612653565b6121d5575f5ffd5b61220083603c846040516020016121ec9190614fd9565b6040516020818303038152906040526118b5565b505050565b5f602052805f5260405f205f915054906101000a900467ffffffffffffffff1681565b6060612235848484612dd8565b90509392505050565b8261224881612653565b612250575f5ffd5b8160075f5f5f8881526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f205f857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916847f7c69f06bea0bdef565b709e93a147836b0063ba2dd89f02d0b7e8d931e6a6daa846040516123829190613bd0565b60405180910390a350505050565b5f600b5f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b60605f60025f5f5f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f209050805f8481526020019081526020015f20805461249590614774565b80601f01602080910402602001604051908101604052809291908181526020018280546124c190614774565b801561250c5780601f106124e35761010080835404028352916020019161250c565b820191905f5260205f20905b8154815290600101906020018083116124ef57829003601f168201915b505050505091505f825114801561253057505f61252884612f9c565b63ffffffff16115b156125d357805f638000000081526020019081526020015f20805461255490614774565b80601f016020809104026020016040519081016040528092919081815260200182805461258090614774565b80156125cb5780601f106125a2576101008083540402835291602001916125cb565b820191905f5260205f20905b8154815290600101906020018083116125ae57829003601f168201915b505050505091505b5092915050565b5f7f59d1d43c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061264c575061264b82612fd2565b5b9050919050565b5f8161265e33611728565b0361266c576001905061284d565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166302571be3846040518263ffffffff1660e01b81526004016126c69190613fbd565b602060405180830381865afa1580156126e1573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127059190615007565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036127f7577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16636352211e845f1c6040518263ffffffff1660e01b81526004016127b59190615032565b602060405180830381865afa1580156127d0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127f49190615007565b90505b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16148061283757506128368133612390565b5b806128495750612848818433611e06565b5b9150505b919050565b61285a61381b565b82815f0181905250818160c001818152505061287581612c73565b92915050565b5f815f015151826020015110159050919050565b60606128bd82602001516128aa845f0151856020015161304b565b845f01516130c49092919063ffffffff16565b9050919050565b60606128f58260a001518360a001518460c001516128e291906146c4565b845f01516130c49092919063ffffffff16565b9050919050565b5f8151835114801561291b575081805190602001208380519060200120145b905092915050565b5f878051906020012090505f6129448686896130c49092919063ffffffff16565b90508315612ad9575f60055f8567ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8c81526020019081526020015f205f8481526020019081526020015f205f8a61ffff1661ffff1681526020019081526020015f2080546129b290614774565b905014612a355760065f8467ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8b81526020019081526020015f205f8381526020019081526020015f205f81819054906101000a900461ffff1680929190612a199061504b565b91906101000a81548161ffff021916908361ffff160217905550505b60055f8467ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8b81526020019081526020015f205f8381526020019081526020015f205f8961ffff1661ffff1681526020019081526020015f205f612a9a9190613860565b897f03528ed0c2a3ebc993b12ce3c16bb382f9c7d88ef7d8a1bf290eaf35955a12078a8a604051612acc929190615081565b60405180910390a2612c67565b5f60055f8567ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8c81526020019081526020015f205f8481526020019081526020015f205f8a61ffff1661ffff1681526020019081526020015f208054612b3f90614774565b905003612bc25760065f8467ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8b81526020019081526020015f205f8381526020019081526020015f205f81819054906101000a900461ffff1680929190612ba6906150af565b91906101000a81548161ffff021916908361ffff160217905550505b8060055f8567ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8c81526020019081526020015f205f8481526020019081526020015f205f8a61ffff1661ffff1681526020019081526020015f209081612c299190614d98565b50897f52a608b3303a48862d07a73d82fa221318c0027fbbcfb1b2329bface3f19ff2b8a8a84604051612c5e939291906150d8565b60405180910390a25b50505050505050505050565b8060c00151816020018181525050805f01515181602001511015612dae575f612ca3825f0151836020015161304b565b8260200151612cb2919061511b565b9050612cca81835f015161312990919063ffffffff16565b826040019061ffff16908161ffff1681525050600281612cea919061511b565b9050612d0281835f015161312990919063ffffffff16565b826060019061ffff16908161ffff1681525050600281612d22919061511b565b9050612d3a81835f015161315290919063ffffffff16565b826080019063ffffffff16908163ffffffff1681525050600481612d5e919061511b565b90505f612d7782845f015161312990919063ffffffff16565b61ffff169050600282612d8a919061511b565b9150818360a00181815250508082612da2919061511b565b8360c001818152505050505b50565b5f6380000000821480612dd157505f612dc983612f9c565b63ffffffff16115b9050919050565b60608282905067ffffffffffffffff811115612df757612df6613fda565b5b604051908082528060200260200182016040528015612e2a57816020015b6060815260200190600190039081612e155790505b5090505f5f90505b83839050811015612f94575f5f1b8514612ecf575f848483818110612e5a57612e59614a9e565b5b9050602002810190612e6c919061515a565b600490602492612e7e939291906151c4565b90612e8991906151fe565b9050858114612ecd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612ec4906152cc565b60405180910390fd5b505b5f5f3073ffffffffffffffffffffffffffffffffffffffff16868685818110612efb57612efa614a9e565b5b9050602002810190612f0d919061515a565b604051612f1b92919061530e565b5f60405180830381855af49150503d805f8114612f53576040519150601f19603f3d011682016040523d82523d5f602084013e612f58565b606091505b509150915081612f66575f5ffd5b80848481518110612f7a57612f79614a9e565b5b602002602001018190525050508080600101915050612e32565b509392505050565b5f603c8203612fae5760019050612fcd565b63800000008218915063800000008210612fc8575f612fca565b815b90505b919050565b5f7fc8690233000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061304457506130438261317b565b5b9050919050565b5f5f8290505b6001156130af578351811061306957613068615326565b5b5f61307d82866131f490919063ffffffff16565b60ff16905060018161308f919061511b565b8261309a919061511b565b91505f81036130a957506130af565b50613051565b82816130bb91906146c4565b91505092915050565b60608167ffffffffffffffff8111156130e0576130df613fda565b5b6040519080825280601f01601f1916602001820160405280156131125781602001600182028036833780820191505090505b5090506131228484835f86613234565b9392505050565b5f6131408360028461313b919061511b565b613284565b8160208401015160f01c905092915050565b5f61316983600484613164919061511b565b613284565b8160208401015160e01c905092915050565b5f7f691f3431000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806131ed57506131ec826132d1565b5b9050919050565b5f61320b83600184613206919061511b565b613284565b82828151811061321e5761321d614a9e565b5b602001015160f81c60f81b60f81c905092915050565b613249858286613244919061511b565b613284565b61325e838284613259919061511b565b613284565b61327d8261326b8561334a565b01856132768861334a565b0183613356565b5050505050565b81518111156132cd578082516040517f8a3c1cfb0000000000000000000000000000000000000000000000000000000081526004016132c4929190615353565b60405180910390fd5b5050565b5f7f124a319c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806133435750613342826133a4565b5b9050919050565b5f602082019050919050565b5b601f81111561337b5781518352602083019250602082019150602081039050613357565b801561339f576001808260200360031b1b0380198351168185511680821786525050505b505050565b5f7fa8fa5682000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061346e57507f5c98042b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061347e575061347d82613485565b5b9050919050565b5f7fbc1c58d1000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806134f757506134f6826134fe565b5b9050919050565b5f817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f3b3b57de000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806135c85750817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167ff1cb7e06000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806136305750817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f32f111d7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80613640575061363f82613647565b5b9050919050565b5f7f2203ab56000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806136b957506136b8826136c0565b5b9050919050565b5f7fd700ff33000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480613732575061373182613739565b5b9050919050565b5f7f4fbf0433000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806137ab57506137aa826137b2565b5b9050919050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b6040518060e00160405280606081526020015f81526020015f61ffff1681526020015f61ffff1681526020015f63ffffffff1681526020015f81526020015f81525090565b50805461386c90614774565b5f825580601f1061387d575061389a565b601f0160209004905f5260205f2090810190613899919061389d565b5b50565b5b808211156138b4575f815f90555060010161389e565b5090565b5f604051905090565b5f5ffd5b5f5ffd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6138fd816138c9565b8114613907575f5ffd5b50565b5f81359050613918816138f4565b92915050565b5f60208284031215613933576139326138c1565b5b5f6139408482850161390a565b91505092915050565b5f8115159050919050565b61395d81613949565b82525050565b5f6020820190506139765f830184613954565b92915050565b5f819050919050565b61398e8161397c565b8114613998575f5ffd5b50565b5f813590506139a981613985565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f8401126139d0576139cf6139af565b5b8235905067ffffffffffffffff8111156139ed576139ec6139b3565b5b602083019150836001820283011115613a0957613a086139b7565b5b9250929050565b5f5f5f60408486031215613a2757613a266138c1565b5b5f613a348682870161399b565b935050602084013567ffffffffffffffff811115613a5557613a546138c5565b5b613a61868287016139bb565b92509250509250925092565b5f5f83601f840112613a8257613a816139af565b5b8235905067ffffffffffffffff811115613a9f57613a9e6139b3565b5b602083019150836001820283011115613abb57613aba6139b7565b5b9250929050565b5f5f5f5f5f60608688031215613adb57613ada6138c1565b5b5f613ae88882890161399b565b955050602086013567ffffffffffffffff811115613b0957613b086138c5565b5b613b1588828901613a6d565b9450945050604086013567ffffffffffffffff811115613b3857613b376138c5565b5b613b4488828901613a6d565b92509250509295509295909350565b5f5f60408385031215613b6957613b686138c1565b5b5f613b768582860161399b565b9250506020613b878582860161390a565b9150509250929050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f613bba82613b91565b9050919050565b613bca81613bb0565b82525050565b5f602082019050613be35f830184613bc1565b92915050565b5f819050919050565b613bfb81613be9565b8114613c05575f5ffd5b50565b5f81359050613c1681613bf2565b92915050565b5f5f60408385031215613c3257613c316138c1565b5b5f613c3f8582860161399b565b9250506020613c5085828601613c08565b9150509250929050565b613c6381613be9565b82525050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f613cab82613c69565b613cb58185613c73565b9350613cc5818560208601613c83565b613cce81613c91565b840191505092915050565b5f604082019050613cec5f830185613c5a565b8181036020830152613cfe8184613ca1565b90509392505050565b5f5f5f60608486031215613d1e57613d1d6138c1565b5b5f613d2b8682870161399b565b9350506020613d3c8682870161399b565b9250506040613d4d8682870161399b565b9150509250925092565b5f60208284031215613d6c57613d6b6138c1565b5b5f613d798482850161399b565b91505092915050565b5f613d8c82613b91565b9050919050565b613d9c81613d82565b82525050565b5f602082019050613db55f830184613d93565b92915050565b5f5f60408385031215613dd157613dd06138c1565b5b5f613dde8582860161399b565b9250506020613def8582860161399b565b9150509250929050565b5f5f5f60408486031215613e1057613e0f6138c1565b5b5f613e1d8682870161399b565b935050602084013567ffffffffffffffff811115613e3e57613e3d6138c5565b5b613e4a86828701613a6d565b92509250509250925092565b5f81519050919050565b5f82825260208201905092915050565b5f613e7a82613e56565b613e848185613e60565b9350613e94818560208601613c83565b613e9d81613c91565b840191505092915050565b5f6020820190508181035f830152613ec08184613e70565b905092915050565b5f6020820190508181035f830152613ee08184613ca1565b905092915050565b5f5f5f5f60608587031215613f0057613eff6138c1565b5b5f613f0d8782880161399b565b9450506020613f1e87828801613c08565b935050604085013567ffffffffffffffff811115613f3f57613f3e6138c5565b5b613f4b878288016139bb565b925092505092959194509250565b613f6281613bb0565b8114613f6c575f5ffd5b50565b5f81359050613f7d81613f59565b92915050565b5f60208284031215613f9857613f976138c1565b5b5f613fa584828501613f6f565b91505092915050565b613fb78161397c565b82525050565b5f602082019050613fd05f830184613fae565b92915050565b5f5ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61401082613c91565b810181811067ffffffffffffffff8211171561402f5761402e613fda565b5b80604052505050565b5f6140416138b8565b905061404d8282614007565b919050565b5f67ffffffffffffffff82111561406c5761406b613fda565b5b61407582613c91565b9050602081019050919050565b828183375f83830152505050565b5f6140a261409d84614052565b614038565b9050828152602081018484840111156140be576140bd613fd6565b5b6140c9848285614082565b509392505050565b5f82601f8301126140e5576140e46139af565b5b81356140f5848260208601614090565b91505092915050565b5f5f5f60608486031215614115576141146138c1565b5b5f6141228682870161399b565b935050602061413386828701613c08565b925050604084013567ffffffffffffffff811115614154576141536138c5565b5b614160868287016140d1565b9150509250925092565b61417381613949565b811461417d575f5ffd5b50565b5f8135905061418e8161416a565b92915050565b5f5f604083850312156141aa576141a96138c1565b5b5f6141b785828601613f6f565b92505060206141c885828601614180565b9150509250929050565b5f5f5f606084860312156141e9576141e86138c1565b5b5f6141f68682870161399b565b935050602061420786828701613f6f565b925050604061421886828701614180565b9150509250925092565b5f61ffff82169050919050565b61423881614222565b8114614242575f5ffd5b50565b5f813590506142538161422f565b92915050565b5f5f5f606084860312156142705761426f6138c1565b5b5f61427d8682870161399b565b935050602061428e8682870161399b565b925050604061429f86828701614245565b9150509250925092565b5f5f5f606084860312156142c0576142bf6138c1565b5b5f6142cd86828701613f6f565b93505060206142de8682870161399b565b92505060406142ef86828701613f6f565b9150509250925092565b5f5f83601f84011261430e5761430d6139af565b5b8235905067ffffffffffffffff81111561432b5761432a6139b3565b5b602083019150836020820283011115614347576143466139b7565b5b9250929050565b5f5f60208385031215614364576143636138c1565b5b5f83013567ffffffffffffffff811115614381576143806138c5565b5b61438d858286016142f9565b92509250509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f82825260208201905092915050565b5f6143dc82613c69565b6143e681856143c2565b93506143f6818560208601613c83565b6143ff81613c91565b840191505092915050565b5f61441583836143d2565b905092915050565b5f602082019050919050565b5f61443382614399565b61443d81856143a3565b93508360208202850161444f856143b3565b805f5b8581101561448a578484038952815161446b858261440a565b94506144768361441d565b925060208a01995050600181019050614452565b50829750879550505050505092915050565b5f6020820190508181035f8301526144b48184614429565b905092915050565b5f6040820190506144cf5f830185613fae565b6144dc6020830184613fae565b9392505050565b5f5f604083850312156144f9576144f86138c1565b5b5f6145068582860161399b565b925050602061451785828601613f6f565b9150509250929050565b5f67ffffffffffffffff82169050919050565b61453d81614521565b82525050565b5f6020820190506145565f830184614534565b92915050565b5f5f5f60408486031215614573576145726138c1565b5b5f6145808682870161399b565b935050602084013567ffffffffffffffff8111156145a1576145a06138c5565b5b6145ad868287016142f9565b92509250509250925092565b5f5f5f606084860312156145d0576145cf6138c1565b5b5f6145dd8682870161399b565b93505060206145ee8682870161390a565b92505060406145ff86828701613f6f565b9150509250925092565b5f5f6040838503121561461f5761461e6138c1565b5b5f61462c85828601613f6f565b925050602061463d85828601613f6f565b9150509250929050565b5f81905092915050565b5f61465b82613c69565b6146658185614647565b9350614675818560208601613c83565b80840191505092915050565b5f61468c8284614651565b915081905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6146ce82613be9565b91506146d983613be9565b92508282039050818111156146f1576146f0614697565b5b92915050565b5f81905092915050565b5f61470c83856146f7565b9350614719838584614082565b82840190509392505050565b5f614731828486614701565b91508190509392505050565b5f82905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061478b57607f821691505b60208210810361479e5761479d614747565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f600883026148007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826147c5565b61480a86836147c5565b95508019841693508086168417925050509392505050565b5f819050919050565b5f61484561484061483b84613be9565b614822565b613be9565b9050919050565b5f819050919050565b61485e8361482b565b61487261486a8261484c565b8484546147d1565b825550505050565b5f5f905090565b61488961487a565b614894818484614855565b505050565b5b818110156148b7576148ac5f82614881565b60018101905061489a565b5050565b601f8211156148fc576148cd816147a4565b6148d6846147b6565b810160208510156148e5578190505b6148f96148f1856147b6565b830182614899565b50505b505050565b5f82821c905092915050565b5f61491c5f1984600802614901565b1980831691505092915050565b5f614934838361490d565b9150826002028217905092915050565b61494e838361473d565b67ffffffffffffffff81111561496757614966613fda565b5b6149718254614774565b61497c8282856148bb565b5f601f8311600181146149a9575f8415614997578287013590505b6149a18582614929565b865550614a08565b601f1984166149b7866147a4565b5f5b828110156149de578489013582556001820191506020850194506020810190506149b9565b868310156149fb57848901356149f7601f89168261490d565b8355505b6001600288020188555050505b50505050505050565b5f614a1c8385613e60565b9350614a29838584614082565b614a3283613c91565b840190509392505050565b5f6040820190508181035f830152614a56818688614a11565b90508181036020830152614a6b818486614a11565b905095945050505050565b614a7f816138c9565b82525050565b5f602082019050614a985f830184614a76565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82905092915050565b5f819050815f5260205f209050919050565b601f821115614b2857614af981614ad5565b614b02846147b6565b81016020851015614b11578190505b614b25614b1d856147b6565b830182614899565b50505b505050565b614b378383614acb565b67ffffffffffffffff811115614b5057614b4f613fda565b5b614b5a8254614774565b614b65828285614ae7565b5f601f831160018114614b92575f8415614b80578287013590505b614b8a8582614929565b865550614bf1565b601f198416614ba086614ad5565b5f5b82811015614bc757848901358255600182019150602085019450602081019050614ba2565b86831015614be45784890135614be0601f89168261490d565b8355505b6001600288020188555050505b50505050505050565b5f614c058385613c73565b9350614c12838584614082565b614c1b83613c91565b840190509392505050565b5f6020820190508181035f830152614c3f818486614bfa565b90509392505050565b5f614c5282614521565b915067ffffffffffffffff8203614c6c57614c6b614697565b5b600182019050919050565b5f819050602082019050919050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b5f614cbc8251614c86565b80915050919050565b5f614ccf82613c69565b82614cd984614c77565b9050614ce481614cb1565b92506014821015614d2457614d1f7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000836014036008026147c5565b831692505b5050919050565b5f819050919050565b614d45614d408261397c565b614d2b565b82525050565b5f614d568285614d34565b602082019150614d668284614d34565b6020820191508190509392505050565b5f6020820190508181035f830152614d8f818486614a11565b90509392505050565b614da182613c69565b67ffffffffffffffff811115614dba57614db9613fda565b5b614dc48254614774565b614dcf828285614ae7565b5f60209050601f831160018114614e00575f8415614dee578287015190505b614df88582614929565b865550614e5f565b601f198416614e0e86614ad5565b5f5b82811015614e3557848901518255600182019150602085019450602081019050614e10565b86831015614e525784890151614e4e601f89168261490d565b8355505b6001600288020188555050505b505050505050565b7f455243313135353a2073657474696e6720617070726f76616c207374617475735f8201527f20666f722073656c660000000000000000000000000000000000000000000000602082015250565b5f614ec1602983613e60565b9150614ecc82614e67565b604082019050919050565b5f6020820190508181035f830152614eee81614eb5565b9050919050565b7f53657474696e672064656c65676174652073746174757320666f722073656c665f82015250565b5f614f29602083613e60565b9150614f3482614ef5565b602082019050919050565b5f6020820190508181035f830152614f5681614f1d565b9050919050565b5f6040820190508181035f830152614f758186613ca1565b90508181036020830152614f8a818486614bfa565b9050949350505050565b5f8160601b9050919050565b5f614faa82614f94565b9050919050565b5f614fbb82614fa0565b9050919050565b614fd3614fce82613bb0565b614fb1565b82525050565b5f614fe48284614fc2565b60148201915081905092915050565b5f8151905061500181613f59565b92915050565b5f6020828403121561501c5761501b6138c1565b5b5f61502984828501614ff3565b91505092915050565b5f6020820190506150455f830184613c5a565b92915050565b5f61505582614222565b91505f820361506757615066614697565b5b600182039050919050565b61507b81614222565b82525050565b5f6040820190508181035f8301526150998185613ca1565b90506150a86020830184615072565b9392505050565b5f6150b982614222565b915061ffff82036150cd576150cc614697565b5b600182019050919050565b5f6060820190508181035f8301526150f08186613ca1565b90506150ff6020830185615072565b81810360408301526151118184613ca1565b9050949350505050565b5f61512582613be9565b915061513083613be9565b925082820190508082111561514857615147614697565b5b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f833560016020038436030381126151765761517561514e565b5b80840192508235915067ffffffffffffffff82111561519857615197615152565b5b6020830192506001820236038313156151b4576151b3615156565b5b509250929050565b5f5ffd5b5f5ffd5b5f5f858511156151d7576151d66151bc565b5b838611156151e8576151e76151c0565b5b6001850283019150848603905094509492505050565b5f6152098383614acb565b82615214813561397c565b925060208210156152545761524f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff836020036008026147c5565b831692505b505092915050565b7f6d756c746963616c6c3a20416c6c207265636f726473206d75737420686176655f8201527f2061206d61746368696e67206e616d6568617368000000000000000000000000602082015250565b5f6152b6603483613e60565b91506152c18261525c565b604082019050919050565b5f6020820190508181035f8301526152e3816152aa565b9050919050565b5f6152f58385614647565b9350615302838584614082565b82840190509392505050565b5f61531a8284866152ea565b91508190509392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52600160045260245ffd5b5f6040820190506153665f830185613c5a565b6153736020830184613c5a565b939250505056fea26469706673582212201be480d91ba1d7407b39b4b1de8dd71fd858485561591354c39d7d78bda5648864736f6c634300081e003300000000000000000000000000000000000c2e074ec69a0dfb2997ba6c7d2e1e0000000000000000000000000635513f179d50a207757e05759cbd106d7dfce8
Deployed Bytecode
0x608060405234801561000f575f5ffd5b50600436106101ee575f3560e01c8063773722131161010d578063c8690233116100a0578063e32954eb1161006f578063e32954eb14610644578063e59d895d14610674578063e985e9c514610690578063f1cb7e06146106c0576101ee565b8063c8690233146105ab578063ce3decdc146105dc578063d5fa2b00146105f8578063d700ff3314610614576101ee565b8063a8fa5682116100dc578063a8fa5682146104eb578063a9784b3e1461051b578063ac9650d81461054b578063bc1c58d11461057b576101ee565b8063773722131461047b5780638b95dd7114610497578063a22cb465146104b3578063a4b91a01146104cf576101ee565b80633603d758116101855780635c98042b116101545780635c98042b146103cf578063623195b0146103ff578063691f34311461041b5780637315937d1461044b576101ee565b80633603d758146103235780633b3b57de1461033f5780634cbf6ba41461036f57806359d1d43c1461039f576101ee565b80632203ab56116101c15780632203ab561461028a57806329cd62ea146102bb578063304e6ade146102d757806332f111d7146102f3576101ee565b806301ffc9a7146101f25780630af179d71461022257806310f13a8c1461023e578063124a319c1461025a575b5f5ffd5b61020c6004803603810190610207919061391e565b6106f0565b6040516102199190613963565b60405180910390f35b61023c60048036038101906102379190613a10565b610701565b005b61025860048036038101906102539190613ac2565b610956565b005b610274600480360381019061026f9190613b53565b610a4b565b6040516102819190613bd0565b60405180910390f35b6102a4600480360381019061029f9190613c1c565b610e8c565b6040516102b2929190613cd9565b60405180910390f35b6102d560048036038101906102d09190613d07565b611005565b005b6102f160048036038101906102ec9190613a10565b6110d8565b005b61030d60048036038101906103089190613c1c565b611191565b60405161031a9190613963565b60405180910390f35b61033d60048036038101906103389190613d57565b61120f565b005b61035960048036038101906103549190613d57565b6112da565b6040516103669190613da2565b60405180910390f35b61038960048036038101906103849190613dbb565b6112f9565b6040516103969190613963565b60405180910390f35b6103b960048036038101906103b49190613df9565b61137d565b6040516103c69190613ea8565b60405180910390f35b6103e960048036038101906103e49190613d57565b611484565b6040516103f69190613ec8565b60405180910390f35b61041960048036038101906104149190613ee8565b61156b565b005b61043560048036038101906104309190613d57565b611641565b6040516104429190613ea8565b60405180910390f35b61046560048036038101906104609190613f83565b611728565b6040516104729190613fbd565b60405180910390f35b61049560048036038101906104909190613df9565b6117fc565b005b6104b160048036038101906104ac91906140fe565b6118b5565b005b6104cd60048036038101906104c89190614194565b611a2e565b005b6104e960048036038101906104e491906141d2565b611b94565b005b61050560048036038101906105009190614259565b611cf7565b6040516105129190613ec8565b60405180910390f35b610535600480360381019061053091906142a9565b611e06565b6040516105429190613963565b60405180910390f35b6105656004803603810190610560919061434e565b611ea4565b604051610572919061449c565b60405180910390f35b61059560048036038101906105909190613d57565b611ebb565b6040516105a29190613ec8565b60405180910390f35b6105c560048036038101906105c09190613d57565b611fa2565b6040516105d39291906144bc565b60405180910390f35b6105f660048036038101906105f19190613a10565b612044565b005b610612600480360381019061060d91906144e3565b6121c3565b005b61062e60048036038101906106299190613d57565b612205565b60405161063b9190614543565b60405180910390f35b61065e6004803603810190610659919061455c565b612228565b60405161066b919061449c565b60405180910390f35b61068e600480360381019061068991906145b9565b61223e565b005b6106aa60048036038101906106a59190614609565b612390565b6040516106b79190613963565b60405180910390f35b6106da60048036038101906106d59190613c1c565b61241e565b6040516106e79190613ec8565b60405180910390f35b5f6106fa826125da565b9050919050565b8261070b81612653565b610713575f5ffd5b5f5f90505f5f90506060805f5f5f5f8b81526020019081526020015f205f9054906101000a900467ffffffffffffffff1690505f61079d5f8b8b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f8201169050808301925050505050505061285290919063ffffffff16565b90505b6107a98161287b565b6108db575f8761ffff160361080357806040015196506107c88161288f565b9450846040516020016107db9190614681565b6040516020818303038152906040528051906020012092506107fc816128c4565b93506108cd565b5f61080d8261288f565b9050816040015161ffff168861ffff1614158061083a575061083881876128fc90919063ffffffff16565b155b156108cb576108a48c878a8e8e8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f820116905080830192505050505050508b8c886020015161089a91906146c4565b5f8c51148a612923565b8160400151975081602001519650809550858051906020012093506108c8826128c4565b94505b505b6108d681612c73565b6107a0565b505f8451111561094a576109498a85888c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f81840152601f19601f82011690508083019250505050505050898a8f8f905061093f91906146c4565b5f8a511488612923565b5b50505050505050505050565b8461096081612653565b610968575f5ffd5b8282600a5f5f5f8b81526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8981526020019081526020015f2087876040516109d1929190614725565b908152602001604051809103902091826109ec929190614944565b5084846040516109fd929190614725565b6040518091039020867f448bc014f1536726cf8d54ff3d6481ed3cbc683c2591ca204274009afa09b1a187878787604051610a3b9493929190614a3d565b60405180910390a3505050505050565b5f5f60075f5f5f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f205f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614610b4f5780915050610e86565b5f610b59856112da565b90505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610b98575f92505050610e86565b5f5f8273ffffffffffffffffffffffffffffffffffffffff167f01ffc9a700000000000000000000000000000000000000000000000000000000604051602401610be29190614a85565b6040516020818303038152906040527f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610c6c9190614681565b5f60405180830381855afa9150503d805f8114610ca4576040519150601f19603f3d011682016040523d82523d5f602084013e610ca9565b606091505b5091509150811580610cbc575060208151105b80610d0957505f60f81b81601f81518110610cda57610cd9614a9e565b5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b15610d1a575f945050505050610e86565b8273ffffffffffffffffffffffffffffffffffffffff1686604051602401610d429190614a85565b6040516020818303038152906040527f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051610dcc9190614681565b5f60405180830381855afa9150503d805f8114610e04576040519150601f19603f3d011682016040523d82523d5f602084013e610e09565b606091505b508092508193505050811580610e20575060208151105b80610e6d57505f60f81b81601f81518110610e3e57610e3d614a9e565b5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b15610e7e575f945050505050610e86565b829450505050505b92915050565b5f60605f60015f5f5f8881526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f2090505f600190505b5f81118015610efe5750848111155b15610fe7575f85821614158015610f3057505f825f8381526020019081526020015f208054610f2c90614774565b9050115b15610fdb5780825f8381526020019081526020015f20808054610f5290614774565b80601f0160208091040260200160405190810160405280929190818152602001828054610f7e90614774565b8015610fc95780601f10610fa057610100808354040283529160200191610fc9565b820191905f5260205f20905b815481529060010190602001808311610fac57829003601f168201915b50505050509050935093505050610ffe565b600181901b9050610eef565b505f60405180602001604052805f81525092509250505b9250929050565b8261100f81612653565b611017575f5ffd5b60405180604001604052808481526020018381525060095f5f5f8881526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f205f820151815f015560208201518160010155905050837f1d6f5e03d3f63eb58751986629a5439baee5079ff04f345becb66e23eb154e4684846040516110ca9291906144bc565b60405180910390a250505050565b826110e281612653565b6110ea575f5ffd5b828260035f5f5f8981526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8781526020019081526020015f209182611150929190614b2d565b50837fe379c1624ed7e714cc0937528a32359d69d5281337765313dba4e081b72d75788484604051611183929190614c26565b60405180910390a250505050565b5f5f60025f5f5f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f8481526020019081526020015f20805461120490614774565b905011905092915050565b8061121981612653565b611221575f5ffd5b5f5f8381526020019081526020015f205f81819054906101000a900467ffffffffffffffff168092919061125490614c48565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555050817fc6621ccb8f3f5a04bb6502154b2caf6adf5983fe76dfef1cfc9c42e3579db4445f5f8581526020019081526020015f205f9054906101000a900467ffffffffffffffff166040516112ce9190614543565b60405180910390a25050565b5f6112e682603c61241e565b6112ef90614cc5565b60601c9050919050565b5f5f60065f5f5f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f8481526020019081526020015f205f9054906101000a900461ffff1661ffff161415905092915050565b6060600a5f5f5f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f2083836040516113e6929190614725565b908152602001604051809103902080546113ff90614774565b80601f016020809104026020016040519081016040528092919081815260200182805461142b90614774565b80156114765780601f1061144d57610100808354040283529160200191611476565b820191905f5260205f20905b81548152906001019060200180831161145957829003601f168201915b505050505090509392505050565b606060045f5f5f8581526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f2080546114e890614774565b80601f016020809104026020016040519081016040528092919081815260200182805461151490614774565b801561155f5780601f106115365761010080835404028352916020019161155f565b820191905f5260205f20905b81548152906001019060200180831161154257829003601f168201915b50505050509050919050565b8361157581612653565b61157d575f5ffd5b5f8460018661158c91906146c4565b1614611596575f5ffd5b828260015f5f5f8a81526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8881526020019081526020015f205f8781526020019081526020015f20918261160b929190614b2d565b5083857faa121bbeef5f32f5961a2a28966e769023910fc9479059ee3495d4c1a696efe360405160405180910390a35050505050565b606060085f5f5f8581526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f2080546116a590614774565b80601f01602080910402602001604051908101604052809291908181526020018280546116d190614774565b801561171c5780601f106116f35761010080835404028352916020019161171c565b820191905f5260205f20905b8154815290600101906020018083116116ff57829003601f168201915b50505050509050919050565b5f5f60285b5f8111156117a2576001810390507f3031323334353637383961626364656600000000000000000000000000000000600f85161a81536010840493506001810390507f3031323334353637383961626364656600000000000000000000000000000000600f85161a815360108404935061172d565b5060285f2090507f91d1777781884d03a6757a803996e38de2a42967fb37eeaca72729271025a9e25f1b816040516020016117de929190614d4b565b60405160208183030381529060405280519060200120915050919050565b8261180681612653565b61180e575f5ffd5b828260085f5f5f8981526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8781526020019081526020015f209182611874929190614944565b50837fb7d29e911041e8d9b843369e890bcb72c9388692ba48b65ac54e7214c4c348f784846040516118a7929190614d76565b60405180910390a250505050565b826118bf81612653565b6118c7575f5ffd5b5f8251141580156118da57506014825114155b80156118eb57506118ea83612db1565b5b1561192d57816040517f8d666f600000000000000000000000000000000000000000000000000000000081526004016119249190613ec8565b60405180910390fd5b837f65412581168e88a1e60c6459d7f44ae83ad0832e670826c05a4e2476b57af752848460405161195f929190613cd9565b60405180910390a2603c83036119b457837f52d7d861f09ab3d26239d492e8968629f95e9e318cf0b73bfddc441522a15fd28361199b90614cc5565b60601c6040516119ab9190613bd0565b60405180910390a25b8160025f5f5f8881526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f205f8581526020019081526020015f209081611a279190614d98565b5050505050565b8173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1603611a9c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a9390614ed7565b60405180910390fd5b80600b5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3183604051611b889190613963565b60405180910390a35050565b8173ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1603611c02576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bf990614f3f565b60405180910390fd5b80600c5f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f6101000a81548160ff0219169083151502179055508015158273ffffffffffffffffffffffffffffffffffffffff16847ff0ddb3b04746704017f9aa8bd728fcc2c1d11675041205350018915f5e4750a033604051611cea9190613bd0565b60405180910390a4505050565b606060055f5f5f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f8481526020019081526020015f205f8361ffff1661ffff1681526020019081526020015f208054611d8190614774565b80601f0160208091040260200160405190810160405280929190818152602001828054611dad90614774565b8015611df85780601f10611dcf57610100808354040283529160200191611df8565b820191905f5260205f20905b815481529060010190602001808311611ddb57829003601f168201915b505050505090509392505050565b5f600c5f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8481526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff1690509392505050565b6060611eb35f5f1b8484612dd8565b905092915050565b606060035f5f5f8581526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8381526020019081526020015f208054611f1f90614774565b80601f0160208091040260200160405190810160405280929190818152602001828054611f4b90614774565b8015611f965780601f10611f6d57610100808354040283529160200191611f96565b820191905f5260205f20905b815481529060010190602001808311611f7957829003601f168201915b50505050509050919050565b5f5f5f5f5f8581526020019081526020015f205f9054906101000a900467ffffffffffffffff16905060095f8267ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f205f015460095f8367ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f20600101549250925050915091565b8261204e81612653565b612056575f5ffd5b5f5f5f8681526020019081526020015f205f9054906101000a900467ffffffffffffffff1690505f60045f8367ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8781526020019081526020015f2080546120bd90614774565b80601f01602080910402602001604051908101604052809291908181526020018280546120e990614774565b80156121345780601f1061210b57610100808354040283529160200191612134565b820191905f5260205f20905b81548152906001019060200180831161211757829003601f168201915b50505050509050848460045f8567ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8981526020019081526020015f20918261217e929190614b2d565b50857f8f15ed4b723ef428f250961da8315675b507046737e19319fc1a4d81bfe87f858287876040516121b393929190614f5d565b60405180910390a2505050505050565b816121cd81612653565b6121d5575f5ffd5b61220083603c846040516020016121ec9190614fd9565b6040516020818303038152906040526118b5565b505050565b5f602052805f5260405f205f915054906101000a900467ffffffffffffffff1681565b6060612235848484612dd8565b90509392505050565b8261224881612653565b612250575f5ffd5b8160075f5f5f8881526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8681526020019081526020015f205f857bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191681526020019081526020015f205f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916847f7c69f06bea0bdef565b709e93a147836b0063ba2dd89f02d0b7e8d931e6a6daa846040516123829190613bd0565b60405180910390a350505050565b5f600b5f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f9054906101000a900460ff16905092915050565b60605f60025f5f5f8781526020019081526020015f205f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8581526020019081526020015f209050805f8481526020019081526020015f20805461249590614774565b80601f01602080910402602001604051908101604052809291908181526020018280546124c190614774565b801561250c5780601f106124e35761010080835404028352916020019161250c565b820191905f5260205f20905b8154815290600101906020018083116124ef57829003601f168201915b505050505091505f825114801561253057505f61252884612f9c565b63ffffffff16115b156125d357805f638000000081526020019081526020015f20805461255490614774565b80601f016020809104026020016040519081016040528092919081815260200182805461258090614774565b80156125cb5780601f106125a2576101008083540402835291602001916125cb565b820191905f5260205f20905b8154815290600101906020018083116125ae57829003601f168201915b505050505091505b5092915050565b5f7f59d1d43c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061264c575061264b82612fd2565b5b9050919050565b5f8161265e33611728565b0361266c576001905061284d565b5f7f00000000000000000000000000000000000c2e074ec69a0dfb2997ba6c7d2e1e73ffffffffffffffffffffffffffffffffffffffff166302571be3846040518263ffffffff1660e01b81526004016126c69190613fbd565b602060405180830381865afa1580156126e1573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127059190615007565b90507f0000000000000000000000000635513f179d50a207757e05759cbd106d7dfce873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036127f7577f0000000000000000000000000635513f179d50a207757e05759cbd106d7dfce873ffffffffffffffffffffffffffffffffffffffff16636352211e845f1c6040518263ffffffff1660e01b81526004016127b59190615032565b602060405180830381865afa1580156127d0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906127f49190615007565b90505b3373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16148061283757506128368133612390565b5b806128495750612848818433611e06565b5b9150505b919050565b61285a61381b565b82815f0181905250818160c001818152505061287581612c73565b92915050565b5f815f015151826020015110159050919050565b60606128bd82602001516128aa845f0151856020015161304b565b845f01516130c49092919063ffffffff16565b9050919050565b60606128f58260a001518360a001518460c001516128e291906146c4565b845f01516130c49092919063ffffffff16565b9050919050565b5f8151835114801561291b575081805190602001208380519060200120145b905092915050565b5f878051906020012090505f6129448686896130c49092919063ffffffff16565b90508315612ad9575f60055f8567ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8c81526020019081526020015f205f8481526020019081526020015f205f8a61ffff1661ffff1681526020019081526020015f2080546129b290614774565b905014612a355760065f8467ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8b81526020019081526020015f205f8381526020019081526020015f205f81819054906101000a900461ffff1680929190612a199061504b565b91906101000a81548161ffff021916908361ffff160217905550505b60055f8467ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8b81526020019081526020015f205f8381526020019081526020015f205f8961ffff1661ffff1681526020019081526020015f205f612a9a9190613860565b897f03528ed0c2a3ebc993b12ce3c16bb382f9c7d88ef7d8a1bf290eaf35955a12078a8a604051612acc929190615081565b60405180910390a2612c67565b5f60055f8567ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8c81526020019081526020015f205f8481526020019081526020015f205f8a61ffff1661ffff1681526020019081526020015f208054612b3f90614774565b905003612bc25760065f8467ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8b81526020019081526020015f205f8381526020019081526020015f205f81819054906101000a900461ffff1680929190612ba6906150af565b91906101000a81548161ffff021916908361ffff160217905550505b8060055f8567ffffffffffffffff1667ffffffffffffffff1681526020019081526020015f205f8c81526020019081526020015f205f8481526020019081526020015f205f8a61ffff1661ffff1681526020019081526020015f209081612c299190614d98565b50897f52a608b3303a48862d07a73d82fa221318c0027fbbcfb1b2329bface3f19ff2b8a8a84604051612c5e939291906150d8565b60405180910390a25b50505050505050505050565b8060c00151816020018181525050805f01515181602001511015612dae575f612ca3825f0151836020015161304b565b8260200151612cb2919061511b565b9050612cca81835f015161312990919063ffffffff16565b826040019061ffff16908161ffff1681525050600281612cea919061511b565b9050612d0281835f015161312990919063ffffffff16565b826060019061ffff16908161ffff1681525050600281612d22919061511b565b9050612d3a81835f015161315290919063ffffffff16565b826080019063ffffffff16908163ffffffff1681525050600481612d5e919061511b565b90505f612d7782845f015161312990919063ffffffff16565b61ffff169050600282612d8a919061511b565b9150818360a00181815250508082612da2919061511b565b8360c001818152505050505b50565b5f6380000000821480612dd157505f612dc983612f9c565b63ffffffff16115b9050919050565b60608282905067ffffffffffffffff811115612df757612df6613fda565b5b604051908082528060200260200182016040528015612e2a57816020015b6060815260200190600190039081612e155790505b5090505f5f90505b83839050811015612f94575f5f1b8514612ecf575f848483818110612e5a57612e59614a9e565b5b9050602002810190612e6c919061515a565b600490602492612e7e939291906151c4565b90612e8991906151fe565b9050858114612ecd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612ec4906152cc565b60405180910390fd5b505b5f5f3073ffffffffffffffffffffffffffffffffffffffff16868685818110612efb57612efa614a9e565b5b9050602002810190612f0d919061515a565b604051612f1b92919061530e565b5f60405180830381855af49150503d805f8114612f53576040519150601f19603f3d011682016040523d82523d5f602084013e612f58565b606091505b509150915081612f66575f5ffd5b80848481518110612f7a57612f79614a9e565b5b602002602001018190525050508080600101915050612e32565b509392505050565b5f603c8203612fae5760019050612fcd565b63800000008218915063800000008210612fc8575f612fca565b815b90505b919050565b5f7fc8690233000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061304457506130438261317b565b5b9050919050565b5f5f8290505b6001156130af578351811061306957613068615326565b5b5f61307d82866131f490919063ffffffff16565b60ff16905060018161308f919061511b565b8261309a919061511b565b91505f81036130a957506130af565b50613051565b82816130bb91906146c4565b91505092915050565b60608167ffffffffffffffff8111156130e0576130df613fda565b5b6040519080825280601f01601f1916602001820160405280156131125781602001600182028036833780820191505090505b5090506131228484835f86613234565b9392505050565b5f6131408360028461313b919061511b565b613284565b8160208401015160f01c905092915050565b5f61316983600484613164919061511b565b613284565b8160208401015160e01c905092915050565b5f7f691f3431000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806131ed57506131ec826132d1565b5b9050919050565b5f61320b83600184613206919061511b565b613284565b82828151811061321e5761321d614a9e565b5b602001015160f81c60f81b60f81c905092915050565b613249858286613244919061511b565b613284565b61325e838284613259919061511b565b613284565b61327d8261326b8561334a565b01856132768861334a565b0183613356565b5050505050565b81518111156132cd578082516040517f8a3c1cfb0000000000000000000000000000000000000000000000000000000081526004016132c4929190615353565b60405180910390fd5b5050565b5f7f124a319c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806133435750613342826133a4565b5b9050919050565b5f602082019050919050565b5b601f81111561337b5781518352602083019250602082019150602081039050613357565b801561339f576001808260200360031b1b0380198351168185511680821786525050505b505050565b5f7fa8fa5682000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916148061346e57507f5c98042b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b8061347e575061347d82613485565b5b9050919050565b5f7fbc1c58d1000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806134f757506134f6826134fe565b5b9050919050565b5f817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f3b3b57de000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806135c85750817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167ff1cb7e06000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b806136305750817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167f32f111d7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b80613640575061363f82613647565b5b9050919050565b5f7f2203ab56000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806136b957506136b8826136c0565b5b9050919050565b5f7fd700ff33000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480613732575061373182613739565b5b9050919050565b5f7f4fbf0433000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff191614806137ab57506137aa826137b2565b5b9050919050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b6040518060e00160405280606081526020015f81526020015f61ffff1681526020015f61ffff1681526020015f63ffffffff1681526020015f81526020015f81525090565b50805461386c90614774565b5f825580601f1061387d575061389a565b601f0160209004905f5260205f2090810190613899919061389d565b5b50565b5b808211156138b4575f815f90555060010161389e565b5090565b5f604051905090565b5f5ffd5b5f5ffd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b6138fd816138c9565b8114613907575f5ffd5b50565b5f81359050613918816138f4565b92915050565b5f60208284031215613933576139326138c1565b5b5f6139408482850161390a565b91505092915050565b5f8115159050919050565b61395d81613949565b82525050565b5f6020820190506139765f830184613954565b92915050565b5f819050919050565b61398e8161397c565b8114613998575f5ffd5b50565b5f813590506139a981613985565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f8401126139d0576139cf6139af565b5b8235905067ffffffffffffffff8111156139ed576139ec6139b3565b5b602083019150836001820283011115613a0957613a086139b7565b5b9250929050565b5f5f5f60408486031215613a2757613a266138c1565b5b5f613a348682870161399b565b935050602084013567ffffffffffffffff811115613a5557613a546138c5565b5b613a61868287016139bb565b92509250509250925092565b5f5f83601f840112613a8257613a816139af565b5b8235905067ffffffffffffffff811115613a9f57613a9e6139b3565b5b602083019150836001820283011115613abb57613aba6139b7565b5b9250929050565b5f5f5f5f5f60608688031215613adb57613ada6138c1565b5b5f613ae88882890161399b565b955050602086013567ffffffffffffffff811115613b0957613b086138c5565b5b613b1588828901613a6d565b9450945050604086013567ffffffffffffffff811115613b3857613b376138c5565b5b613b4488828901613a6d565b92509250509295509295909350565b5f5f60408385031215613b6957613b686138c1565b5b5f613b768582860161399b565b9250506020613b878582860161390a565b9150509250929050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f613bba82613b91565b9050919050565b613bca81613bb0565b82525050565b5f602082019050613be35f830184613bc1565b92915050565b5f819050919050565b613bfb81613be9565b8114613c05575f5ffd5b50565b5f81359050613c1681613bf2565b92915050565b5f5f60408385031215613c3257613c316138c1565b5b5f613c3f8582860161399b565b9250506020613c5085828601613c08565b9150509250929050565b613c6381613be9565b82525050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f613cab82613c69565b613cb58185613c73565b9350613cc5818560208601613c83565b613cce81613c91565b840191505092915050565b5f604082019050613cec5f830185613c5a565b8181036020830152613cfe8184613ca1565b90509392505050565b5f5f5f60608486031215613d1e57613d1d6138c1565b5b5f613d2b8682870161399b565b9350506020613d3c8682870161399b565b9250506040613d4d8682870161399b565b9150509250925092565b5f60208284031215613d6c57613d6b6138c1565b5b5f613d798482850161399b565b91505092915050565b5f613d8c82613b91565b9050919050565b613d9c81613d82565b82525050565b5f602082019050613db55f830184613d93565b92915050565b5f5f60408385031215613dd157613dd06138c1565b5b5f613dde8582860161399b565b9250506020613def8582860161399b565b9150509250929050565b5f5f5f60408486031215613e1057613e0f6138c1565b5b5f613e1d8682870161399b565b935050602084013567ffffffffffffffff811115613e3e57613e3d6138c5565b5b613e4a86828701613a6d565b92509250509250925092565b5f81519050919050565b5f82825260208201905092915050565b5f613e7a82613e56565b613e848185613e60565b9350613e94818560208601613c83565b613e9d81613c91565b840191505092915050565b5f6020820190508181035f830152613ec08184613e70565b905092915050565b5f6020820190508181035f830152613ee08184613ca1565b905092915050565b5f5f5f5f60608587031215613f0057613eff6138c1565b5b5f613f0d8782880161399b565b9450506020613f1e87828801613c08565b935050604085013567ffffffffffffffff811115613f3f57613f3e6138c5565b5b613f4b878288016139bb565b925092505092959194509250565b613f6281613bb0565b8114613f6c575f5ffd5b50565b5f81359050613f7d81613f59565b92915050565b5f60208284031215613f9857613f976138c1565b5b5f613fa584828501613f6f565b91505092915050565b613fb78161397c565b82525050565b5f602082019050613fd05f830184613fae565b92915050565b5f5ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61401082613c91565b810181811067ffffffffffffffff8211171561402f5761402e613fda565b5b80604052505050565b5f6140416138b8565b905061404d8282614007565b919050565b5f67ffffffffffffffff82111561406c5761406b613fda565b5b61407582613c91565b9050602081019050919050565b828183375f83830152505050565b5f6140a261409d84614052565b614038565b9050828152602081018484840111156140be576140bd613fd6565b5b6140c9848285614082565b509392505050565b5f82601f8301126140e5576140e46139af565b5b81356140f5848260208601614090565b91505092915050565b5f5f5f60608486031215614115576141146138c1565b5b5f6141228682870161399b565b935050602061413386828701613c08565b925050604084013567ffffffffffffffff811115614154576141536138c5565b5b614160868287016140d1565b9150509250925092565b61417381613949565b811461417d575f5ffd5b50565b5f8135905061418e8161416a565b92915050565b5f5f604083850312156141aa576141a96138c1565b5b5f6141b785828601613f6f565b92505060206141c885828601614180565b9150509250929050565b5f5f5f606084860312156141e9576141e86138c1565b5b5f6141f68682870161399b565b935050602061420786828701613f6f565b925050604061421886828701614180565b9150509250925092565b5f61ffff82169050919050565b61423881614222565b8114614242575f5ffd5b50565b5f813590506142538161422f565b92915050565b5f5f5f606084860312156142705761426f6138c1565b5b5f61427d8682870161399b565b935050602061428e8682870161399b565b925050604061429f86828701614245565b9150509250925092565b5f5f5f606084860312156142c0576142bf6138c1565b5b5f6142cd86828701613f6f565b93505060206142de8682870161399b565b92505060406142ef86828701613f6f565b9150509250925092565b5f5f83601f84011261430e5761430d6139af565b5b8235905067ffffffffffffffff81111561432b5761432a6139b3565b5b602083019150836020820283011115614347576143466139b7565b5b9250929050565b5f5f60208385031215614364576143636138c1565b5b5f83013567ffffffffffffffff811115614381576143806138c5565b5b61438d858286016142f9565b92509250509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f819050602082019050919050565b5f82825260208201905092915050565b5f6143dc82613c69565b6143e681856143c2565b93506143f6818560208601613c83565b6143ff81613c91565b840191505092915050565b5f61441583836143d2565b905092915050565b5f602082019050919050565b5f61443382614399565b61443d81856143a3565b93508360208202850161444f856143b3565b805f5b8581101561448a578484038952815161446b858261440a565b94506144768361441d565b925060208a01995050600181019050614452565b50829750879550505050505092915050565b5f6020820190508181035f8301526144b48184614429565b905092915050565b5f6040820190506144cf5f830185613fae565b6144dc6020830184613fae565b9392505050565b5f5f604083850312156144f9576144f86138c1565b5b5f6145068582860161399b565b925050602061451785828601613f6f565b9150509250929050565b5f67ffffffffffffffff82169050919050565b61453d81614521565b82525050565b5f6020820190506145565f830184614534565b92915050565b5f5f5f60408486031215614573576145726138c1565b5b5f6145808682870161399b565b935050602084013567ffffffffffffffff8111156145a1576145a06138c5565b5b6145ad868287016142f9565b92509250509250925092565b5f5f5f606084860312156145d0576145cf6138c1565b5b5f6145dd8682870161399b565b93505060206145ee8682870161390a565b92505060406145ff86828701613f6f565b9150509250925092565b5f5f6040838503121561461f5761461e6138c1565b5b5f61462c85828601613f6f565b925050602061463d85828601613f6f565b9150509250929050565b5f81905092915050565b5f61465b82613c69565b6146658185614647565b9350614675818560208601613c83565b80840191505092915050565b5f61468c8284614651565b915081905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6146ce82613be9565b91506146d983613be9565b92508282039050818111156146f1576146f0614697565b5b92915050565b5f81905092915050565b5f61470c83856146f7565b9350614719838584614082565b82840190509392505050565b5f614731828486614701565b91508190509392505050565b5f82905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061478b57607f821691505b60208210810361479e5761479d614747565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f600883026148007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826147c5565b61480a86836147c5565b95508019841693508086168417925050509392505050565b5f819050919050565b5f61484561484061483b84613be9565b614822565b613be9565b9050919050565b5f819050919050565b61485e8361482b565b61487261486a8261484c565b8484546147d1565b825550505050565b5f5f905090565b61488961487a565b614894818484614855565b505050565b5b818110156148b7576148ac5f82614881565b60018101905061489a565b5050565b601f8211156148fc576148cd816147a4565b6148d6846147b6565b810160208510156148e5578190505b6148f96148f1856147b6565b830182614899565b50505b505050565b5f82821c905092915050565b5f61491c5f1984600802614901565b1980831691505092915050565b5f614934838361490d565b9150826002028217905092915050565b61494e838361473d565b67ffffffffffffffff81111561496757614966613fda565b5b6149718254614774565b61497c8282856148bb565b5f601f8311600181146149a9575f8415614997578287013590505b6149a18582614929565b865550614a08565b601f1984166149b7866147a4565b5f5b828110156149de578489013582556001820191506020850194506020810190506149b9565b868310156149fb57848901356149f7601f89168261490d565b8355505b6001600288020188555050505b50505050505050565b5f614a1c8385613e60565b9350614a29838584614082565b614a3283613c91565b840190509392505050565b5f6040820190508181035f830152614a56818688614a11565b90508181036020830152614a6b818486614a11565b905095945050505050565b614a7f816138c9565b82525050565b5f602082019050614a985f830184614a76565b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f82905092915050565b5f819050815f5260205f209050919050565b601f821115614b2857614af981614ad5565b614b02846147b6565b81016020851015614b11578190505b614b25614b1d856147b6565b830182614899565b50505b505050565b614b378383614acb565b67ffffffffffffffff811115614b5057614b4f613fda565b5b614b5a8254614774565b614b65828285614ae7565b5f601f831160018114614b92575f8415614b80578287013590505b614b8a8582614929565b865550614bf1565b601f198416614ba086614ad5565b5f5b82811015614bc757848901358255600182019150602085019450602081019050614ba2565b86831015614be45784890135614be0601f89168261490d565b8355505b6001600288020188555050505b50505050505050565b5f614c058385613c73565b9350614c12838584614082565b614c1b83613c91565b840190509392505050565b5f6020820190508181035f830152614c3f818486614bfa565b90509392505050565b5f614c5282614521565b915067ffffffffffffffff8203614c6c57614c6b614697565b5b600182019050919050565b5f819050602082019050919050565b5f7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000082169050919050565b5f614cbc8251614c86565b80915050919050565b5f614ccf82613c69565b82614cd984614c77565b9050614ce481614cb1565b92506014821015614d2457614d1f7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000836014036008026147c5565b831692505b5050919050565b5f819050919050565b614d45614d408261397c565b614d2b565b82525050565b5f614d568285614d34565b602082019150614d668284614d34565b6020820191508190509392505050565b5f6020820190508181035f830152614d8f818486614a11565b90509392505050565b614da182613c69565b67ffffffffffffffff811115614dba57614db9613fda565b5b614dc48254614774565b614dcf828285614ae7565b5f60209050601f831160018114614e00575f8415614dee578287015190505b614df88582614929565b865550614e5f565b601f198416614e0e86614ad5565b5f5b82811015614e3557848901518255600182019150602085019450602081019050614e10565b86831015614e525784890151614e4e601f89168261490d565b8355505b6001600288020188555050505b505050505050565b7f455243313135353a2073657474696e6720617070726f76616c207374617475735f8201527f20666f722073656c660000000000000000000000000000000000000000000000602082015250565b5f614ec1602983613e60565b9150614ecc82614e67565b604082019050919050565b5f6020820190508181035f830152614eee81614eb5565b9050919050565b7f53657474696e672064656c65676174652073746174757320666f722073656c665f82015250565b5f614f29602083613e60565b9150614f3482614ef5565b602082019050919050565b5f6020820190508181035f830152614f5681614f1d565b9050919050565b5f6040820190508181035f830152614f758186613ca1565b90508181036020830152614f8a818486614bfa565b9050949350505050565b5f8160601b9050919050565b5f614faa82614f94565b9050919050565b5f614fbb82614fa0565b9050919050565b614fd3614fce82613bb0565b614fb1565b82525050565b5f614fe48284614fc2565b60148201915081905092915050565b5f8151905061500181613f59565b92915050565b5f6020828403121561501c5761501b6138c1565b5b5f61502984828501614ff3565b91505092915050565b5f6020820190506150455f830184613c5a565b92915050565b5f61505582614222565b91505f820361506757615066614697565b5b600182039050919050565b61507b81614222565b82525050565b5f6040820190508181035f8301526150998185613ca1565b90506150a86020830184615072565b9392505050565b5f6150b982614222565b915061ffff82036150cd576150cc614697565b5b600182019050919050565b5f6060820190508181035f8301526150f08186613ca1565b90506150ff6020830185615072565b81810360408301526151118184613ca1565b9050949350505050565b5f61512582613be9565b915061513083613be9565b925082820190508082111561514857615147614697565b5b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f833560016020038436030381126151765761517561514e565b5b80840192508235915067ffffffffffffffff82111561519857615197615152565b5b6020830192506001820236038313156151b4576151b3615156565b5b509250929050565b5f5ffd5b5f5ffd5b5f5f858511156151d7576151d66151bc565b5b838611156151e8576151e76151c0565b5b6001850283019150848603905094509492505050565b5f6152098383614acb565b82615214813561397c565b925060208210156152545761524f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff836020036008026147c5565b831692505b505092915050565b7f6d756c746963616c6c3a20416c6c207265636f726473206d75737420686176655f8201527f2061206d61746368696e67206e616d6568617368000000000000000000000000602082015250565b5f6152b6603483613e60565b91506152c18261525c565b604082019050919050565b5f6020820190508181035f8301526152e3816152aa565b9050919050565b5f6152f58385614647565b9350615302838584614082565b82840190509392505050565b5f61531a8284866152ea565b91508190509392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52600160045260245ffd5b5f6040820190506153665f830185613c5a565b6153736020830184613c5a565b939250505056fea26469706673582212201be480d91ba1d7407b39b4b1de8dd71fd858485561591354c39d7d78bda5648864736f6c634300081e0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000c2e074ec69a0dfb2997ba6c7d2e1e0000000000000000000000000635513f179d50a207757e05759cbd106d7dfce8
-----Decoded View---------------
Arg [0] : _ens (address): 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e
Arg [1] : wrapperAddress (address): 0x0635513f179D50A207757E05759CbD106d7dFcE8
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000c2e074ec69a0dfb2997ba6c7d2e1e
Arg [1] : 0000000000000000000000000635513f179d50a207757e05759cbd106d7dfce8
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.