Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Latest 13 from a total of 13 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
Amount
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Verify RR Set | 10294061 | 21 days ago | IN | 0 ETH | 0.00195761 | ||||
| Verify RR Set | 10293261 | 21 days ago | IN | 0 ETH | 0.00195196 | ||||
| Verify RR Set | 9985762 | 66 days ago | IN | 0 ETH | 0.00079441 | ||||
| Verify RR Set | 9985561 | 66 days ago | IN | 0 ETH | 0.00079439 | ||||
| Verify RR Set | 9902784 | 78 days ago | IN | 0 ETH | 0.00081537 | ||||
| Verify RR Set | 9901783 | 79 days ago | IN | 0 ETH | 0.00081005 | ||||
| Verify RR Set | 9896854 | 79 days ago | IN | 0 ETH | 0.00000054 | ||||
| Set Anchors | 9896740 | 79 days ago | IN | 0 ETH | 0.00000003 | ||||
| Set Anchors | 9896723 | 79 days ago | IN | 0 ETH | 0.00000006 | ||||
| Set Anchors | 9896710 | 79 days ago | IN | 0 ETH | 0.00000025 | ||||
| Set Digest | 9896670 | 79 days ago | IN | 0 ETH | 0.00000004 | ||||
| Set Algorithm | 9896670 | 79 days ago | IN | 0 ETH | 0.00000004 | ||||
| Set Algorithm | 9896670 | 79 days ago | IN | 0 ETH | 0.00000004 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Loading...
Loading
Contract Name:
DNSSECOracle
Compiler Version
v0.8.25+commit.b61c2a91
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "./Owned.sol";
import "./DNSSEC.sol";
import "./libraries/RRUtils.sol";
import "./interfaces/IAlgorithm.sol";
import "./interfaces/IDigest.sol";
import "./utils/BytesUtils.sol";
import "@ensdomains/buffer/contracts/Buffer.sol";
/**
* @title DNSSECOracle
* @dev Verifies DNSSEC proofs using Algorithm 8 (RSA/SHA-256) and Algorithm 13 (P-256/SHA-256).
* Based on ENS's DNSSECImpl.sol but optimized for the EIP-7951 P-256 precompile.
*
* @notice Key differences from ENS DNSSECImpl:
* - Uses EIP-7951 precompile for Algorithm 13 (~3k gas vs ~400k gas)
* - Same trust model: full DS chain from IANA root
* - Same wire format parsing via RRUtils
*/
contract DNSSECOracle is DNSSEC, Owned {
using Buffer for Buffer.buffer;
using BytesUtils for bytes;
using RRUtils for *;
// DNS constants
uint16 constant DNSCLASS_IN = 1;
uint16 constant DNSTYPE_DS = 43;
uint16 constant DNSTYPE_DNSKEY = 48;
uint256 constant DNSKEY_FLAG_ZONEKEY = 0x100;
// Custom errors for gas efficiency
error InvalidLabelCount(bytes name, uint256 labelsExpected);
error SignatureNotValidYet(uint32 inception, uint32 now);
error SignatureExpired(uint32 expiration, uint32 now);
error InvalidClass(uint16 class);
error InvalidRRSet();
error SignatureTypeMismatch(uint16 rrsetType, uint16 sigType);
error InvalidSignerName(bytes rrsetName, bytes signerName);
error InvalidProofType(uint16 proofType);
error ProofNameMismatch(bytes signerName, bytes proofName);
error NoMatchingProof(bytes signerName);
error AlgorithmNotSupported(uint8 algorithm);
error DigestNotSupported(uint8 digestType);
// Registries for pluggable algorithms and digests
mapping(uint8 => IAlgorithm) public algorithms;
mapping(uint8 => IDigest) public digests;
/**
* @dev Constructor.
* @param _anchors The binary format RR entries for the root DS records.
* These are the IANA trust anchors that start the chain of trust.
*/
constructor(bytes memory _anchors) {
anchors = _anchors;
}
/**
* @dev Sets the trust anchors (IANA root DS records).
* Can only be called by the owner.
* @param _anchors The binary format RR entries for the root DS records.
*/
function setAnchors(bytes memory _anchors) public owner_only {
anchors = _anchors;
}
/**
* @dev Sets the contract address for a signature verification algorithm.
* @param id The algorithm ID (8 = RSA/SHA-256, 13 = P-256/SHA-256)
* @param algo The address of the algorithm contract.
*/
function setAlgorithm(uint8 id, IAlgorithm algo) public owner_only {
algorithms[id] = algo;
emit AlgorithmUpdated(id, address(algo));
}
/**
* @dev Sets the contract address for a digest verification algorithm.
* @param id The digest ID (2 = SHA-256)
* @param digest The address of the digest contract.
*/
function setDigest(uint8 id, IDigest digest) public owner_only {
digests[id] = digest;
emit DigestUpdated(id, address(digest));
}
/**
* @dev Verifies a chain of signed DNS records.
* @param input A list of signed RRSets forming a chain of trust.
* @return rrs The RRData from the last RRSet in the chain.
* @return inception The inception time of the signed record set.
*/
function verifyRRSet(
RRSetWithSignature[] memory input
)
external
view
virtual
override
returns (bytes memory rrs, uint32 inception)
{
return verifyRRSet(input, block.timestamp);
}
/**
* @dev Verifies a chain of signed DNS records at a specific time.
* @param input A list of signed RRSets forming a chain of trust.
* @param timestamp The Unix timestamp to validate the records at.
* @return rrs The RRData from the last RRSet in the chain.
* @return inception The inception time of the signed record set.
*/
function verifyRRSet(
RRSetWithSignature[] memory input,
uint256 timestamp
)
public
view
virtual
override
returns (bytes memory rrs, uint32 inception)
{
// Start with the trust anchors (root DS records)
bytes memory proof = anchors;
// Validate each RRSet in the chain
for (uint256 i = 0; i < input.length; i++) {
RRUtils.SignedSet memory rrset = validateSignedSet(
input[i],
proof,
timestamp
);
proof = rrset.data;
inception = rrset.inception;
}
return (proof, inception);
}
/**
* @dev Validates an RRSet against an already trusted RR.
* @param input The signed RR set with RRSIG data.
* @param proof The DNSKEY or DS to validate the signature against.
* @param timestamp The current timestamp.
* @return rrset The parsed and validated SignedSet.
*/
function validateSignedSet(
RRSetWithSignature memory input,
bytes memory proof,
uint256 timestamp
) internal view returns (RRUtils.SignedSet memory rrset) {
// Parse the RRSIG header and RRset data
rrset = input.rrset.readSignedSet();
// Validate RRs and extract the name
bytes memory name = validateRRs(rrset, rrset.typeCovered);
// Verify label count matches (RFC4035 requirement)
if (name.labelCount(0) != rrset.labels) {
revert InvalidLabelCount(name, rrset.labels);
}
rrset.name = name;
// Time validation using RFC1982 serial number arithmetic
// Signature must not have expired
if (!RRUtils.serialNumberGte(rrset.expiration, uint32(timestamp))) {
revert SignatureExpired(rrset.expiration, uint32(timestamp));
}
// Signature must be valid (inception time passed)
if (!RRUtils.serialNumberGte(uint32(timestamp), rrset.inception)) {
revert SignatureNotValidYet(rrset.inception, uint32(timestamp));
}
// Validate the cryptographic signature
verifySignature(name, rrset, input, proof);
return rrset;
}
/**
* @dev Validates a set of RRs for consistency.
* @param rrset The RR set.
* @param typecovered The type covered by the RRSIG record.
* @return name The DNS name from the RRs.
*/
function validateRRs(
RRUtils.SignedSet memory rrset,
uint16 typecovered
) internal pure returns (bytes memory name) {
for (
RRUtils.RRIterator memory iter = rrset.rrs();
!iter.done();
iter.next()
) {
// Only support class IN (Internet)
if (iter.class != DNSCLASS_IN) {
revert InvalidClass(iter.class);
}
if (name.length == 0) {
name = iter.name();
} else {
// All RRs must have the same name
if (
name.length != iter.data.nameLength(iter.offset) ||
!name.equals(0, iter.data, iter.offset, name.length)
) {
revert InvalidRRSet();
}
}
// RRSIG type covered must match RR type
if (iter.dnstype != typecovered) {
revert SignatureTypeMismatch(iter.dnstype, typecovered);
}
}
}
/**
* @dev Performs signature verification using the appropriate proof type.
* @param name The DNS name being verified.
* @param rrset The parsed RRset.
* @param data The original signed data.
* @param proof A DS or DNSKEY record that's already verified.
*/
function verifySignature(
bytes memory name,
RRUtils.SignedSet memory rrset,
RRSetWithSignature memory data,
bytes memory proof
) internal view {
// Signer's Name must be the zone that contains the RRset
if (!name.isSubdomainOf(rrset.signerName)) {
revert InvalidSignerName(name, rrset.signerName);
}
RRUtils.RRIterator memory proofRR = proof.iterateRRs(0);
// Dispatch based on proof type
if (proofRR.dnstype == DNSTYPE_DS) {
verifyWithDS(rrset, data, proofRR);
} else if (proofRR.dnstype == DNSTYPE_DNSKEY) {
verifyWithKnownKey(rrset, data, proofRR);
} else {
revert InvalidProofType(proofRR.dnstype);
}
}
/**
* @dev Verifies a signed RRSET against an already known public key (DNSKEY).
* @param rrset The signed set to verify.
* @param data The original data with signature.
* @param proof The DNSKEY records to verify against.
*/
function verifyWithKnownKey(
RRUtils.SignedSet memory rrset,
RRSetWithSignature memory data,
RRUtils.RRIterator memory proof
) internal view {
for (; !proof.done(); proof.next()) {
bytes memory proofName = proof.name();
if (!proofName.equals(rrset.signerName)) {
revert ProofNameMismatch(rrset.signerName, proofName);
}
bytes memory keyrdata = proof.rdata();
RRUtils.DNSKEY memory dnskey = keyrdata.readDNSKEY(
0,
keyrdata.length
);
if (verifySignatureWithKey(dnskey, keyrdata, rrset, data)) {
return;
}
}
revert NoMatchingProof(rrset.signerName);
}
/**
* @dev Attempts to verify data using a specific DNSKEY.
* @param dnskey The parsed DNSKEY.
* @param keyrdata The raw DNSKEY RDATA.
* @param rrset The signed RRSET.
* @param data The original signed data.
* @return True if the signature is valid.
*/
function verifySignatureWithKey(
RRUtils.DNSKEY memory dnskey,
bytes memory keyrdata,
RRUtils.SignedSet memory rrset,
RRSetWithSignature memory data
) internal view returns (bool) {
// Protocol Field MUST be 3 (RFC4034 2.1.2)
if (dnskey.protocol != 3) {
return false;
}
// Algorithm must match
if (dnskey.algorithm != rrset.algorithm) {
return false;
}
// Key tag must match
uint16 computedkeytag = keyrdata.computeKeytag();
if (computedkeytag != rrset.keytag) {
return false;
}
// Zone Flag bit must be set
if (dnskey.flags & DNSKEY_FLAG_ZONEKEY == 0) {
return false;
}
// Get the algorithm contract
IAlgorithm algorithm = algorithms[dnskey.algorithm];
if (address(algorithm) == address(0)) {
return false;
}
// Verify the signature
return algorithm.verify(keyrdata, data.rrset, data.sig);
}
/**
* @dev Verifies a signed RRSET against DS records (for DNSKEY self-signatures).
* @param rrset The signed set to verify.
* @param data The original data with signature.
* @param proof The DS records to verify against.
*/
function verifyWithDS(
RRUtils.SignedSet memory rrset,
RRSetWithSignature memory data,
RRUtils.RRIterator memory proof
) internal view {
uint256 proofOffset = proof.offset;
// Iterate through each DNSKEY in the RRset
for (
RRUtils.RRIterator memory iter = rrset.rrs();
!iter.done();
iter.next()
) {
if (iter.dnstype != DNSTYPE_DNSKEY) {
revert InvalidProofType(iter.dnstype);
}
bytes memory keyrdata = iter.rdata();
RRUtils.DNSKEY memory dnskey = keyrdata.readDNSKEY(
0,
keyrdata.length
);
// Check if this key signs the RRset
if (verifySignatureWithKey(dnskey, keyrdata, rrset, data)) {
// It's self-signed - verify against DS record
if (verifyKeyWithDS(rrset.signerName, proof, dnskey, keyrdata)) {
return;
}
// Rewind proof iterator for next DNSKEY attempt
proof.nextOffset = proofOffset;
proof.next();
}
}
revert NoMatchingProof(rrset.signerName);
}
/**
* @dev Verifies a DNSKEY against DS records.
* @param keyname The DNS name of the key.
* @param dsrrs The DS records to verify against.
* @param dnskey The parsed DNSKEY.
* @param keyrdata The raw DNSKEY RDATA.
* @return True if a DS record verifies this key.
*/
function verifyKeyWithDS(
bytes memory keyname,
RRUtils.RRIterator memory dsrrs,
RRUtils.DNSKEY memory dnskey,
bytes memory keyrdata
) internal view returns (bool) {
uint16 keytag = keyrdata.computeKeytag();
for (; !dsrrs.done(); dsrrs.next()) {
bytes memory proofName = dsrrs.name();
if (!proofName.equals(keyname)) {
revert ProofNameMismatch(keyname, proofName);
}
RRUtils.DS memory ds = dsrrs.data.readDS(
dsrrs.rdataOffset,
dsrrs.nextOffset - dsrrs.rdataOffset
);
// Skip if key tag doesn't match
if (ds.keytag != keytag) {
continue;
}
// Skip if algorithm doesn't match
if (ds.algorithm != dnskey.algorithm) {
continue;
}
// Compute the digest: SHA256(name || DNSKEY RDATA)
Buffer.buffer memory buf;
buf.init(keyname.length + keyrdata.length);
buf.append(keyname);
buf.append(keyrdata);
if (verifyDSHash(ds.digestType, buf.buf, ds.digest)) {
return true;
}
}
return false;
}
/**
* @dev Verifies a DS record's hash against computed data.
* @param digesttype The digest type from the DS record.
* @param data The data to hash.
* @param digest The expected digest value.
* @return True if the digest matches.
*/
function verifyDSHash(
uint8 digesttype,
bytes memory data,
bytes memory digest
) internal view returns (bool) {
IDigest digestContract = digests[digesttype];
if (address(digestContract) == address(0)) {
return false;
}
return digestContract.verify(data, digest);
}
/**
* @dev Returns the trust anchor (root DS records).
* @return The anchors bytes.
*/
function getAnchors() external view returns (bytes memory) {
return anchors;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @dev Contract mixin for 'owned' contracts.
contract Owned {
address public owner;
modifier owner_only() {
require(msg.sender == owner);
_;
}
constructor() {
owner = msg.sender;
}
function setOwner(address newOwner) public owner_only {
owner = newOwner;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
abstract contract DNSSEC {
bytes public anchors;
struct RRSetWithSignature {
bytes rrset;
bytes sig;
}
event AlgorithmUpdated(uint8 id, address addr);
event DigestUpdated(uint8 id, address addr);
function verifyRRSet(
RRSetWithSignature[] memory input
) external view virtual returns (bytes memory rrs, uint32 inception);
function verifyRRSet(
RRSetWithSignature[] memory input,
uint256 timestamp
) public view virtual returns (bytes memory rrs, uint32 inception);
}//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;
/**
* @dev Interface for DNSSEC signature verification algorithms
*/
interface IAlgorithm {
/**
* @dev Verifies a signature over provided data
* @param key The public key to verify with (DNSKEY RDATA format)
* @param data The data the signature is signing (canonical RRset)
* @param signature The signature data
* @return True if the signature is valid
*/
function verify(
bytes calldata key,
bytes calldata data,
bytes calldata signature
) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @dev Interface for DNSSEC digest verification algorithms
interface IDigest {
/// @dev Verifies a cryptographic hash.
/// @param data The data to hash.
/// @param hash The hash to compare to.
/// @return True iff the hashed data matches the provided hash value.
function verify(
bytes calldata data,
bytes calldata hash
) external pure returns (bool);
}//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: 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
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 {
// 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 {
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 {
ret := mload(src)
}
}
}{
"remappings": [
"forge-std/=lib/forge-std/src/",
"@ensdomains/=node_modules/@ensdomains/",
"@openzeppelin/=node_modules/@openzeppelin/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false
}Contract ABI
API[{"inputs":[{"internalType":"bytes","name":"_anchors","type":"bytes"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint8","name":"algorithm","type":"uint8"}],"name":"AlgorithmNotSupported","type":"error"},{"inputs":[{"internalType":"uint8","name":"digestType","type":"uint8"}],"name":"DigestNotSupported","type":"error"},{"inputs":[{"internalType":"uint16","name":"class","type":"uint16"}],"name":"InvalidClass","type":"error"},{"inputs":[{"internalType":"bytes","name":"name","type":"bytes"},{"internalType":"uint256","name":"labelsExpected","type":"uint256"}],"name":"InvalidLabelCount","type":"error"},{"inputs":[{"internalType":"uint16","name":"proofType","type":"uint16"}],"name":"InvalidProofType","type":"error"},{"inputs":[],"name":"InvalidRRSet","type":"error"},{"inputs":[{"internalType":"bytes","name":"rrsetName","type":"bytes"},{"internalType":"bytes","name":"signerName","type":"bytes"}],"name":"InvalidSignerName","type":"error"},{"inputs":[{"internalType":"bytes","name":"signerName","type":"bytes"}],"name":"NoMatchingProof","type":"error"},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"length","type":"uint256"}],"name":"OffsetOutOfBoundsError","type":"error"},{"inputs":[{"internalType":"bytes","name":"signerName","type":"bytes"},{"internalType":"bytes","name":"proofName","type":"bytes"}],"name":"ProofNameMismatch","type":"error"},{"inputs":[{"internalType":"uint32","name":"expiration","type":"uint32"},{"internalType":"uint32","name":"now","type":"uint32"}],"name":"SignatureExpired","type":"error"},{"inputs":[{"internalType":"uint32","name":"inception","type":"uint32"},{"internalType":"uint32","name":"now","type":"uint32"}],"name":"SignatureNotValidYet","type":"error"},{"inputs":[{"internalType":"uint16","name":"rrsetType","type":"uint16"},{"internalType":"uint16","name":"sigType","type":"uint16"}],"name":"SignatureTypeMismatch","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"id","type":"uint8"},{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"AlgorithmUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"id","type":"uint8"},{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"DigestUpdated","type":"event"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"algorithms","outputs":[{"internalType":"contract IAlgorithm","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"anchors","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"","type":"uint8"}],"name":"digests","outputs":[{"internalType":"contract IDigest","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAnchors","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"id","type":"uint8"},{"internalType":"contract IAlgorithm","name":"algo","type":"address"}],"name":"setAlgorithm","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_anchors","type":"bytes"}],"name":"setAnchors","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"id","type":"uint8"},{"internalType":"contract IDigest","name":"digest","type":"address"}],"name":"setDigest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"rrset","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct DNSSEC.RRSetWithSignature[]","name":"input","type":"tuple[]"},{"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"verifyRRSet","outputs":[{"internalType":"bytes","name":"rrs","type":"bytes"},{"internalType":"uint32","name":"inception","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"rrset","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct DNSSEC.RRSetWithSignature[]","name":"input","type":"tuple[]"}],"name":"verifyRRSet","outputs":[{"internalType":"bytes","name":"rrs","type":"bytes"},{"internalType":"uint32","name":"inception","type":"uint32"}],"stateMutability":"view","type":"function"}]Contract Creation Code
608060405234801561000f575f80fd5b50604051611fa2380380611fa283398101604081905261002e91610066565b600180546001600160a01b031916331790555f61004b8282610194565b5050610253565b634e487b7160e01b5f52604160045260245ffd5b5f60208284031215610076575f80fd5b81516001600160401b038082111561008c575f80fd5b818401915084601f83011261009f575f80fd5b8151818111156100b1576100b1610052565b604051601f8201601f19908116603f011681019083821181831017156100d9576100d9610052565b816040528281528760208487010111156100f1575f80fd5b8260208601602083015e5f928101602001929092525095945050505050565b600181811c9082168061012457607f821691505b60208210810361014257634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561018f57805f5260205f20601f840160051c8101602085101561016d5750805b601f840160051c820191505b8181101561018c575f8155600101610179565b50505b505050565b81516001600160401b038111156101ad576101ad610052565b6101c1816101bb8454610110565b84610148565b602080601f8311600181146101f4575f84156101dd5750858301515b5f19600386901b1c1916600185901b17855561024b565b5f85815260208120601f198616915b8281101561022257888601518255948401946001909101908401610203565b508582101561023f57878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b611d42806102605f395ff3fe608060405234801561000f575f80fd5b50600436106100a6575f3560e01c806373cc48a61161006e57806373cc48a6146101225780638da5cb5b1461016257806398d35f2014610175578063bdf95fef1461018a578063c327deef1461019d578063effb3c6e146101c5575f80fd5b8063020ed8d3146100aa57806313af4035146100bf57806328e7677d146100d2578063440f3d42146100e55780636cbbf64d1461010f575b5f80fd5b6100bd6100b8366004611745565b6101cd565b005b6100bd6100cd36600461177a565b61024d565b6100bd6100e0366004611745565b610285565b6100f86100f336600461195e565b6102fd565b6040516101069291906119ce565b60405180910390f35b6100bd61011d3660046119f5565b6103de565b61014a610130366004611a27565b60036020525f90815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610106565b60015461014a906001600160a01b031681565b61017d610403565b6040516101069190611a40565b6100f8610198366004611a52565b61048e565b61014a6101ab366004611a27565b60026020525f90815260409020546001600160a01b031681565b61017d6104a4565b6001546001600160a01b031633146101e3575f80fd5b60ff82165f8181526002602090815260409182902080546001600160a01b0319166001600160a01b0386169081179091558251938452908301527ff73c3c226af96b7f1ba666a21b3ceaf2be3ee6a365e3178fd9cd1eaae0075aa891015b60405180910390a15050565b6001546001600160a01b03163314610263575f80fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b0316331461029b575f80fd5b60ff82165f8181526003602090815260409182902080546001600160a01b0319166001600160a01b0386169081179091558251938452908301527f2fcc274c3b72dd483ab201bfa87295e3817e8b9b10693219873b722ca1af00c79101610241565b60605f805f805461030d90611a84565b80601f016020809104026020016040519081016040528092919081815260200182805461033990611a84565b80156103845780601f1061035b57610100808354040283529160200191610384565b820191905f5260205f20905b81548152906001019060200180831161036757829003601f168201915b505050505090505f5b85518110156103d4575f6103bb8783815181106103ac576103ac611abc565b60200260200101518488610533565b61010081015160a090910151945092505060010161038d565b5091509250929050565b6001546001600160a01b031633146103f4575f80fd5b5f6103ff8282611b14565b5050565b5f805461040f90611a84565b80601f016020809104026020016040519081016040528092919081815260200182805461043b90611a84565b80156104865780601f1061045d57610100808354040283529160200191610486565b820191905f5260205f20905b81548152906001019060200180831161046957829003601f168201915b505050505081565b60605f61049b83426102fd565b91509150915091565b60605f80546104b290611a84565b80601f01602080910402602001604051908101604052809291908181526020018280546104de90611a84565b80156105295780601f1061050057610100808354040283529160200191610529565b820191905f5260205f20905b81548152906001019060200180831161050c57829003601f168201915b5050505050905090565b61053b61167f565b83516105469061063a565b90505f61055682835f0151610733565b604083015190915060ff1661056b825f610842565b1461059a5780826040015160405163e861b2bd60e01b8152600401610591929190611bd4565b60405180910390fd5b610120820181905260808201515f9084900360030b12156105e45760808201516040516353c27c3f60e11b815263ffffffff91821660048201529084166024820152604401610591565b60a08201515f90840360030b12156106255760a0820151604051635ea081b560e11b815263ffffffff91821660048201529084166024820152604401610591565b610631818387876108a5565b505b9392505050565b61064261167f565b61064c825f610955565b61ffff16815261065d826002610976565b60ff166020820152610670826003610976565b60ff1660408201526106838260046109a8565b63ffffffff908116606083015261069f9083906008906109a816565b63ffffffff90811660808301526106bb908390600c906109a816565b63ffffffff90811660a08301526106d790839060109061095516565b61ffff1660c08201526106eb8260126109c4565b60e082018190525161072890610702906012611c0c565b8260e0015151601285516107169190611c1f565b6107209190611c1f565b8491906109e6565b610100820152919050565b60605f61073f84610a3b565b90505b8051516020820151101561083b57606081015161ffff16600114610785576060810151604051634c52f98d60e11b815261ffff9091166004820152602401610591565b81515f0361079d5761079681610a52565b91506107ed565b602081015181516107ad91610a73565b82511415806107cf57508051602082015183516107cd9285925f92610aca565b155b156107ed5760405163cbceee6f60e01b815260040160405180910390fd5b8261ffff16816040015161ffff161461082d57604080820151905163537fc54560e11b815261ffff91821660048201529084166024820152604401610591565b61083681610aec565b610742565b5092915050565b5f805b8351831061085557610855611c32565b5f6108608585610976565b60ff169050610870816001611c0c565b61087a9085611c0c565b9350805f03610889575061089c565b610894600183611c0c565b915050610845565b90505b92915050565b60e08301516108b5908590610bd1565b6108d95760e083015160405163eaafc59b60e01b8152610591918691600401611c46565b5f6108e48282610c2a565b9050602b61ffff16816040015161ffff160361090a57610905848483610c45565b61094e565b603061ffff16816040015161ffff160361092957610905848483610d2e565b60408082015190516361529e8760e01b815261ffff9091166004820152602401610591565b5050505050565b5f61096a83610965846002611c0c565b610df2565b50016020015160f01c90565b5f61098683610965846001611c0c565b82828151811061099857610998611abc565b016020015160f81c905092915050565b5f6109b883610965846004611c0c565b50016020015160e01c90565b60605f6109d18484610a73565b90506109de8484836109e6565b949350505050565b60608167ffffffffffffffff811115610a0157610a01611795565b6040519080825280601f01601f191660200182016040528015610a2b576020820181803683370190505b5090506106338484835f86610e21565b610a436116d4565b61089f8261010001515f610c2a565b6020810151815160609161089f91610a6a9082610a73565b845191906109e6565b5f815b83518110610a8657610a86611c32565b5f610a918583610976565b60ff169050610aa1816001611c0c565b610aab9083611c0c565b9150805f03610aba5750610ac0565b50610a76565b6109de8382611c1f565b5f610ad6848484610e52565b610ae1878785610e52565b149695505050505050565b60c08101516020820181905281515111610b035750565b5f610b15825f01518360200151610a73565b8260200151610b249190611c0c565b8251909150610b339082610955565b61ffff166040830152610b47600282611c0c565b8251909150610b569082610955565b61ffff166060830152610b6a600282611c0c565b8251909150610b7990826109a8565b63ffffffff166080830152610b8f600482611c0c565b82519091505f90610ba09083610955565b61ffff169050610bb1600283611c0c565b60a084018190529150610bc48183611c0c565b60c0909301929092525050565b5f8080610bde8582610842565b90505f610beb855f610842565b90505b80821115610c1457610c008684610e6b565b925081610c0c81611c6a565b925050610bee565b610c208684875f610e8e565b9695505050505050565b610c326116d4565b82815260c0810182905261089f81610aec565b60208101515f610c5485610a3b565b90505b80515160208201511015610d0e57604081015161ffff16603014610c9a5760408082015190516361529e8760e01b815261ffff9091166004820152602401610591565b5f610ca482610ec9565b90505f610cbd5f835184610ee59092919063ffffffff16565b9050610ccb81838989610f81565b15610cfe57610ce08760e0015186838561109c565b15610cee5750505050505050565b60c08501849052610cfe85610aec565b5050610d0981610aec565b610c57565b508360e001516040516306cde0f360e01b81526004016105919190611a40565b80515160208201511015610dd3575f610d4682610a52565b9050610d5f8460e00151826111d290919063ffffffff16565b610d84578360e0015181604051636b80573f60e11b8152600401610591929190611c46565b5f610d8e83610ec9565b90505f610da75f835184610ee59092919063ffffffff16565b9050610db581838888610f81565b15610dc257505050505050565b505050610dce81610aec565b610d2e565b8260e001516040516306cde0f360e01b81526004016105919190611a40565b81518111156103ff578151604051638a3c1cfb60e01b8152610591918391600401918252602082015260400190565b610e2f856109658387611c0c565b610e3d836109658385611c0c565b61094e826020850101856020880101836111f6565b5f610e61846109658486611c0c565b5091016020012090565b5f610e768383610976565b60ff16610e84836001611c0c565b61089c9190611c0c565b5f610e998585610df2565b610ea38383610df2565b610eb1838384865103610e52565b610ebf868687895103610e52565b1495945050505050565b60a081015160c082015160609161089f91610a6a908290611c1f565b604080516080810182525f8082526020820181905291810191909152606080820152610f1b610f145f85611c0c565b8590610955565b61ffff168152610f36610f2f600285611c0c565b8590610976565b60ff166020820152610f4c610f2f600385611c0c565b60ff166040820152610f75610f62600485611c0c565b610f6d600485611c1f565b8691906109e6565b60608201529392505050565b5f846020015160ff16600314610f9857505f6109de565b826020015160ff16856040015160ff1614610fb457505f6109de565b5f610fbe8561123f565b90508360c0015161ffff168161ffff1614610fdc575f9150506109de565b8551610100165f03610ff1575f9150506109de565b60408087015160ff165f908152600260205220546001600160a01b03168061101d575f925050506109de565b8351602085015160405163de8f50a160e01b81526001600160a01b0384169263de8f50a192611052928b929190600401611c7f565b602060405180830381865afa15801561106d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110919190611cb7565b979650505050505050565b5f806110a78361123f565b90505b845151602086015110156111c7575f6110c286610a52565b90506110ce81886111d2565b6110ef578681604051636b80573f60e11b8152600401610591929190611c46565b60a086015160c08701515f916111139161110a908290611c1f565b89519190610ee5565b90508261ffff16815f015161ffff161461112e5750506111b9565b856040015160ff16816020015160ff161461114a5750506111b9565b60408051808201909152606081525f602082015261117686518a5161116f9190611c0c565b829061145e565b50611181818a6114d2565b5061118c81876114d2565b506111a38260400151825f015184606001516114f2565b156111b55760019450505050506109de565b5050505b6111c285610aec565b6110aa565b505f95945050505050565b5f8151835114801561089c5750508051602091820120825192909101919091201490565b5b601f811115611217578151835260209283019290910190601f19016111f7565b801561123a57815183516001602084900360031b1b5f1901801990921691161783525b505050565b5f612000825111156112935760405162461bcd60e51b815260206004820152601760248201527f4c6f6e67206b657973206e6f74207065726d69747465640000000000000000006044820152606401610591565b5f805f5b8451601f01811015611305575f81602087010151905085518260200111156112cb5785518290036008026101000390811c901b5b7eff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff600882901c81169490940193169190910190602001611297565b506010827fffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff000016901c827dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff160191506010817fffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff000016901c817dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff1601905080600883901b0191506020827fffffffff00000000ffffffff00000000ffffffff00000000ffffffff0000000016901c827bffffffff00000000ffffffff00000000ffffffff00000000ffffffff1601915060408277ffffffffffffffff0000000000000000ffffffffffffffff1916901c8277ffffffffffffffff0000000000000000ffffffffffffffff16019150608082901c826fffffffffffffffffffffffffffffffff16019150601082901c61ffff16820191508192505050919050565b60408051808201909152606081525f602082015261147d602083611cd6565b156114a55761148d602083611cd6565b611498906020611c1f565b6114a29083611c0c565b91505b60208084018390526040518085525f81529081840101818110156114c7575f80fd5b604052509192915050565b60408051808201909152606081525f602082015261089c83838451611591565b60ff83165f908152600360205260408120546001600160a01b03168061151b575f915050610633565b604051637bf41d7760e11b81526001600160a01b0382169063f7e83aee906115499087908790600401611c46565b602060405180830381865afa158015611564573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115889190611cb7565b95945050505050565b60408051808201909152606081525f602082015282518211156115b2575f80fd5b8351515f6115c08483611c0c565b905085602001518111156115e2576115e2866115dd836002611cf5565b611662565b85518051838201602001915f91808511156115fb578482525b505050602086015b6020861061163b578051825261161a602083611c0c565b9150611627602082611c0c565b9050611634602087611c1f565b9550611603565b5181515f1960208890036101000a0190811690199190911617905250849150509392505050565b815161166e838361145e565b5061167983826114d2565b50505050565b60408051610140810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c082019290925260e08101829052610100810182905261012081019190915290565b6040518060e00160405280606081526020015f81526020015f61ffff1681526020015f61ffff1681526020015f63ffffffff1681526020015f81526020015f81525090565b803560ff81168114611729575f80fd5b919050565b6001600160a01b0381168114611742575f80fd5b50565b5f8060408385031215611756575f80fd5b61175f83611719565b9150602083013561176f8161172e565b809150509250929050565b5f6020828403121561178a575f80fd5b813561089c8161172e565b634e487b7160e01b5f52604160045260245ffd5b6040805190810167ffffffffffffffff811182821017156117cc576117cc611795565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156117fb576117fb611795565b604052919050565b5f82601f830112611812575f80fd5b813567ffffffffffffffff81111561182c5761182c611795565b61183f601f8201601f19166020016117d2565b818152846020838601011115611853575f80fd5b816020850160208301375f918101602001919091529392505050565b5f82601f83011261187e575f80fd5b8135602067ffffffffffffffff8083111561189b5761189b611795565b8260051b6118aa8382016117d2565b93845285810183019383810190888611156118c3575f80fd5b84880192505b85831015611952578235848111156118df575f80fd5b88016040818b03601f19018113156118f5575f80fd5b6118fd6117a9565b878301358781111561190d575f80fd5b61191b8d8a83870101611803565b82525090820135908682111561192f575f80fd5b61193d8c8984860101611803565b818901528452505091840191908401906118c9565b98975050505050505050565b5f806040838503121561196f575f80fd5b823567ffffffffffffffff811115611985575f80fd5b6119918582860161186f565b95602094909401359450505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b604081525f6119e060408301856119a0565b905063ffffffff831660208301529392505050565b5f60208284031215611a05575f80fd5b813567ffffffffffffffff811115611a1b575f80fd5b6109de84828501611803565b5f60208284031215611a37575f80fd5b61089c82611719565b602081525f61089c60208301846119a0565b5f60208284031215611a62575f80fd5b813567ffffffffffffffff811115611a78575f80fd5b6109de8482850161186f565b600181811c90821680611a9857607f821691505b602082108103611ab657634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52603260045260245ffd5b601f82111561123a57805f5260205f20601f840160051c81016020851015611af55750805b601f840160051c820191505b8181101561094e575f8155600101611b01565b815167ffffffffffffffff811115611b2e57611b2e611795565b611b4281611b3c8454611a84565b84611ad0565b602080601f831160018114611b75575f8415611b5e5750858301515b5f19600386901b1c1916600185901b178555611bcc565b5f85815260208120601f198616915b82811015611ba357888601518255948401946001909101908401611b84565b5085821015611bc057878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b604081525f611be660408301856119a0565b905060ff831660208301529392505050565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561089f5761089f611bf8565b8181038181111561089f5761089f611bf8565b634e487b7160e01b5f52600160045260245ffd5b604081525f611c5860408301856119a0565b828103602084015261158881856119a0565b5f81611c7857611c78611bf8565b505f190190565b606081525f611c9160608301866119a0565b8281036020840152611ca381866119a0565b90508281036040840152610c2081856119a0565b5f60208284031215611cc7575f80fd5b8151801515811461089c575f80fd5b5f82611cf057634e487b7160e01b5f52601260045260245ffd5b500690565b808202811582820484141761089f5761089f611bf856fea26469706673582212207d56f97fb401fd73c22a6ed6081b715565628f205b9ddf7a26fc309bd092e91664736f6c6343000819003300000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561000f575f80fd5b50600436106100a6575f3560e01c806373cc48a61161006e57806373cc48a6146101225780638da5cb5b1461016257806398d35f2014610175578063bdf95fef1461018a578063c327deef1461019d578063effb3c6e146101c5575f80fd5b8063020ed8d3146100aa57806313af4035146100bf57806328e7677d146100d2578063440f3d42146100e55780636cbbf64d1461010f575b5f80fd5b6100bd6100b8366004611745565b6101cd565b005b6100bd6100cd36600461177a565b61024d565b6100bd6100e0366004611745565b610285565b6100f86100f336600461195e565b6102fd565b6040516101069291906119ce565b60405180910390f35b6100bd61011d3660046119f5565b6103de565b61014a610130366004611a27565b60036020525f90815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610106565b60015461014a906001600160a01b031681565b61017d610403565b6040516101069190611a40565b6100f8610198366004611a52565b61048e565b61014a6101ab366004611a27565b60026020525f90815260409020546001600160a01b031681565b61017d6104a4565b6001546001600160a01b031633146101e3575f80fd5b60ff82165f8181526002602090815260409182902080546001600160a01b0319166001600160a01b0386169081179091558251938452908301527ff73c3c226af96b7f1ba666a21b3ceaf2be3ee6a365e3178fd9cd1eaae0075aa891015b60405180910390a15050565b6001546001600160a01b03163314610263575f80fd5b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b0316331461029b575f80fd5b60ff82165f8181526003602090815260409182902080546001600160a01b0319166001600160a01b0386169081179091558251938452908301527f2fcc274c3b72dd483ab201bfa87295e3817e8b9b10693219873b722ca1af00c79101610241565b60605f805f805461030d90611a84565b80601f016020809104026020016040519081016040528092919081815260200182805461033990611a84565b80156103845780601f1061035b57610100808354040283529160200191610384565b820191905f5260205f20905b81548152906001019060200180831161036757829003601f168201915b505050505090505f5b85518110156103d4575f6103bb8783815181106103ac576103ac611abc565b60200260200101518488610533565b61010081015160a090910151945092505060010161038d565b5091509250929050565b6001546001600160a01b031633146103f4575f80fd5b5f6103ff8282611b14565b5050565b5f805461040f90611a84565b80601f016020809104026020016040519081016040528092919081815260200182805461043b90611a84565b80156104865780601f1061045d57610100808354040283529160200191610486565b820191905f5260205f20905b81548152906001019060200180831161046957829003601f168201915b505050505081565b60605f61049b83426102fd565b91509150915091565b60605f80546104b290611a84565b80601f01602080910402602001604051908101604052809291908181526020018280546104de90611a84565b80156105295780601f1061050057610100808354040283529160200191610529565b820191905f5260205f20905b81548152906001019060200180831161050c57829003601f168201915b5050505050905090565b61053b61167f565b83516105469061063a565b90505f61055682835f0151610733565b604083015190915060ff1661056b825f610842565b1461059a5780826040015160405163e861b2bd60e01b8152600401610591929190611bd4565b60405180910390fd5b610120820181905260808201515f9084900360030b12156105e45760808201516040516353c27c3f60e11b815263ffffffff91821660048201529084166024820152604401610591565b60a08201515f90840360030b12156106255760a0820151604051635ea081b560e11b815263ffffffff91821660048201529084166024820152604401610591565b610631818387876108a5565b505b9392505050565b61064261167f565b61064c825f610955565b61ffff16815261065d826002610976565b60ff166020820152610670826003610976565b60ff1660408201526106838260046109a8565b63ffffffff908116606083015261069f9083906008906109a816565b63ffffffff90811660808301526106bb908390600c906109a816565b63ffffffff90811660a08301526106d790839060109061095516565b61ffff1660c08201526106eb8260126109c4565b60e082018190525161072890610702906012611c0c565b8260e0015151601285516107169190611c1f565b6107209190611c1f565b8491906109e6565b610100820152919050565b60605f61073f84610a3b565b90505b8051516020820151101561083b57606081015161ffff16600114610785576060810151604051634c52f98d60e11b815261ffff9091166004820152602401610591565b81515f0361079d5761079681610a52565b91506107ed565b602081015181516107ad91610a73565b82511415806107cf57508051602082015183516107cd9285925f92610aca565b155b156107ed5760405163cbceee6f60e01b815260040160405180910390fd5b8261ffff16816040015161ffff161461082d57604080820151905163537fc54560e11b815261ffff91821660048201529084166024820152604401610591565b61083681610aec565b610742565b5092915050565b5f805b8351831061085557610855611c32565b5f6108608585610976565b60ff169050610870816001611c0c565b61087a9085611c0c565b9350805f03610889575061089c565b610894600183611c0c565b915050610845565b90505b92915050565b60e08301516108b5908590610bd1565b6108d95760e083015160405163eaafc59b60e01b8152610591918691600401611c46565b5f6108e48282610c2a565b9050602b61ffff16816040015161ffff160361090a57610905848483610c45565b61094e565b603061ffff16816040015161ffff160361092957610905848483610d2e565b60408082015190516361529e8760e01b815261ffff9091166004820152602401610591565b5050505050565b5f61096a83610965846002611c0c565b610df2565b50016020015160f01c90565b5f61098683610965846001611c0c565b82828151811061099857610998611abc565b016020015160f81c905092915050565b5f6109b883610965846004611c0c565b50016020015160e01c90565b60605f6109d18484610a73565b90506109de8484836109e6565b949350505050565b60608167ffffffffffffffff811115610a0157610a01611795565b6040519080825280601f01601f191660200182016040528015610a2b576020820181803683370190505b5090506106338484835f86610e21565b610a436116d4565b61089f8261010001515f610c2a565b6020810151815160609161089f91610a6a9082610a73565b845191906109e6565b5f815b83518110610a8657610a86611c32565b5f610a918583610976565b60ff169050610aa1816001611c0c565b610aab9083611c0c565b9150805f03610aba5750610ac0565b50610a76565b6109de8382611c1f565b5f610ad6848484610e52565b610ae1878785610e52565b149695505050505050565b60c08101516020820181905281515111610b035750565b5f610b15825f01518360200151610a73565b8260200151610b249190611c0c565b8251909150610b339082610955565b61ffff166040830152610b47600282611c0c565b8251909150610b569082610955565b61ffff166060830152610b6a600282611c0c565b8251909150610b7990826109a8565b63ffffffff166080830152610b8f600482611c0c565b82519091505f90610ba09083610955565b61ffff169050610bb1600283611c0c565b60a084018190529150610bc48183611c0c565b60c0909301929092525050565b5f8080610bde8582610842565b90505f610beb855f610842565b90505b80821115610c1457610c008684610e6b565b925081610c0c81611c6a565b925050610bee565b610c208684875f610e8e565b9695505050505050565b610c326116d4565b82815260c0810182905261089f81610aec565b60208101515f610c5485610a3b565b90505b80515160208201511015610d0e57604081015161ffff16603014610c9a5760408082015190516361529e8760e01b815261ffff9091166004820152602401610591565b5f610ca482610ec9565b90505f610cbd5f835184610ee59092919063ffffffff16565b9050610ccb81838989610f81565b15610cfe57610ce08760e0015186838561109c565b15610cee5750505050505050565b60c08501849052610cfe85610aec565b5050610d0981610aec565b610c57565b508360e001516040516306cde0f360e01b81526004016105919190611a40565b80515160208201511015610dd3575f610d4682610a52565b9050610d5f8460e00151826111d290919063ffffffff16565b610d84578360e0015181604051636b80573f60e11b8152600401610591929190611c46565b5f610d8e83610ec9565b90505f610da75f835184610ee59092919063ffffffff16565b9050610db581838888610f81565b15610dc257505050505050565b505050610dce81610aec565b610d2e565b8260e001516040516306cde0f360e01b81526004016105919190611a40565b81518111156103ff578151604051638a3c1cfb60e01b8152610591918391600401918252602082015260400190565b610e2f856109658387611c0c565b610e3d836109658385611c0c565b61094e826020850101856020880101836111f6565b5f610e61846109658486611c0c565b5091016020012090565b5f610e768383610976565b60ff16610e84836001611c0c565b61089c9190611c0c565b5f610e998585610df2565b610ea38383610df2565b610eb1838384865103610e52565b610ebf868687895103610e52565b1495945050505050565b60a081015160c082015160609161089f91610a6a908290611c1f565b604080516080810182525f8082526020820181905291810191909152606080820152610f1b610f145f85611c0c565b8590610955565b61ffff168152610f36610f2f600285611c0c565b8590610976565b60ff166020820152610f4c610f2f600385611c0c565b60ff166040820152610f75610f62600485611c0c565b610f6d600485611c1f565b8691906109e6565b60608201529392505050565b5f846020015160ff16600314610f9857505f6109de565b826020015160ff16856040015160ff1614610fb457505f6109de565b5f610fbe8561123f565b90508360c0015161ffff168161ffff1614610fdc575f9150506109de565b8551610100165f03610ff1575f9150506109de565b60408087015160ff165f908152600260205220546001600160a01b03168061101d575f925050506109de565b8351602085015160405163de8f50a160e01b81526001600160a01b0384169263de8f50a192611052928b929190600401611c7f565b602060405180830381865afa15801561106d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110919190611cb7565b979650505050505050565b5f806110a78361123f565b90505b845151602086015110156111c7575f6110c286610a52565b90506110ce81886111d2565b6110ef578681604051636b80573f60e11b8152600401610591929190611c46565b60a086015160c08701515f916111139161110a908290611c1f565b89519190610ee5565b90508261ffff16815f015161ffff161461112e5750506111b9565b856040015160ff16816020015160ff161461114a5750506111b9565b60408051808201909152606081525f602082015261117686518a5161116f9190611c0c565b829061145e565b50611181818a6114d2565b5061118c81876114d2565b506111a38260400151825f015184606001516114f2565b156111b55760019450505050506109de565b5050505b6111c285610aec565b6110aa565b505f95945050505050565b5f8151835114801561089c5750508051602091820120825192909101919091201490565b5b601f811115611217578151835260209283019290910190601f19016111f7565b801561123a57815183516001602084900360031b1b5f1901801990921691161783525b505050565b5f612000825111156112935760405162461bcd60e51b815260206004820152601760248201527f4c6f6e67206b657973206e6f74207065726d69747465640000000000000000006044820152606401610591565b5f805f5b8451601f01811015611305575f81602087010151905085518260200111156112cb5785518290036008026101000390811c901b5b7eff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff600882901c81169490940193169190910190602001611297565b506010827fffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff000016901c827dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff160191506010817fffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff000016901c817dffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff1601905080600883901b0191506020827fffffffff00000000ffffffff00000000ffffffff00000000ffffffff0000000016901c827bffffffff00000000ffffffff00000000ffffffff00000000ffffffff1601915060408277ffffffffffffffff0000000000000000ffffffffffffffff1916901c8277ffffffffffffffff0000000000000000ffffffffffffffff16019150608082901c826fffffffffffffffffffffffffffffffff16019150601082901c61ffff16820191508192505050919050565b60408051808201909152606081525f602082015261147d602083611cd6565b156114a55761148d602083611cd6565b611498906020611c1f565b6114a29083611c0c565b91505b60208084018390526040518085525f81529081840101818110156114c7575f80fd5b604052509192915050565b60408051808201909152606081525f602082015261089c83838451611591565b60ff83165f908152600360205260408120546001600160a01b03168061151b575f915050610633565b604051637bf41d7760e11b81526001600160a01b0382169063f7e83aee906115499087908790600401611c46565b602060405180830381865afa158015611564573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115889190611cb7565b95945050505050565b60408051808201909152606081525f602082015282518211156115b2575f80fd5b8351515f6115c08483611c0c565b905085602001518111156115e2576115e2866115dd836002611cf5565b611662565b85518051838201602001915f91808511156115fb578482525b505050602086015b6020861061163b578051825261161a602083611c0c565b9150611627602082611c0c565b9050611634602087611c1f565b9550611603565b5181515f1960208890036101000a0190811690199190911617905250849150509392505050565b815161166e838361145e565b5061167983826114d2565b50505050565b60408051610140810182525f8082526020820181905291810182905260608082018390526080820183905260a0820183905260c082019290925260e08101829052610100810182905261012081019190915290565b6040518060e00160405280606081526020015f81526020015f61ffff1681526020015f61ffff1681526020015f63ffffffff1681526020015f81526020015f81525090565b803560ff81168114611729575f80fd5b919050565b6001600160a01b0381168114611742575f80fd5b50565b5f8060408385031215611756575f80fd5b61175f83611719565b9150602083013561176f8161172e565b809150509250929050565b5f6020828403121561178a575f80fd5b813561089c8161172e565b634e487b7160e01b5f52604160045260245ffd5b6040805190810167ffffffffffffffff811182821017156117cc576117cc611795565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156117fb576117fb611795565b604052919050565b5f82601f830112611812575f80fd5b813567ffffffffffffffff81111561182c5761182c611795565b61183f601f8201601f19166020016117d2565b818152846020838601011115611853575f80fd5b816020850160208301375f918101602001919091529392505050565b5f82601f83011261187e575f80fd5b8135602067ffffffffffffffff8083111561189b5761189b611795565b8260051b6118aa8382016117d2565b93845285810183019383810190888611156118c3575f80fd5b84880192505b85831015611952578235848111156118df575f80fd5b88016040818b03601f19018113156118f5575f80fd5b6118fd6117a9565b878301358781111561190d575f80fd5b61191b8d8a83870101611803565b82525090820135908682111561192f575f80fd5b61193d8c8984860101611803565b818901528452505091840191908401906118c9565b98975050505050505050565b5f806040838503121561196f575f80fd5b823567ffffffffffffffff811115611985575f80fd5b6119918582860161186f565b95602094909401359450505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b604081525f6119e060408301856119a0565b905063ffffffff831660208301529392505050565b5f60208284031215611a05575f80fd5b813567ffffffffffffffff811115611a1b575f80fd5b6109de84828501611803565b5f60208284031215611a37575f80fd5b61089c82611719565b602081525f61089c60208301846119a0565b5f60208284031215611a62575f80fd5b813567ffffffffffffffff811115611a78575f80fd5b6109de8482850161186f565b600181811c90821680611a9857607f821691505b602082108103611ab657634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52603260045260245ffd5b601f82111561123a57805f5260205f20601f840160051c81016020851015611af55750805b601f840160051c820191505b8181101561094e575f8155600101611b01565b815167ffffffffffffffff811115611b2e57611b2e611795565b611b4281611b3c8454611a84565b84611ad0565b602080601f831160018114611b75575f8415611b5e5750858301515b5f19600386901b1c1916600185901b178555611bcc565b5f85815260208120601f198616915b82811015611ba357888601518255948401946001909101908401611b84565b5085821015611bc057878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b604081525f611be660408301856119a0565b905060ff831660208301529392505050565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561089f5761089f611bf8565b8181038181111561089f5761089f611bf8565b634e487b7160e01b5f52600160045260245ffd5b604081525f611c5860408301856119a0565b828103602084015261158881856119a0565b5f81611c7857611c78611bf8565b505f190190565b606081525f611c9160608301866119a0565b8281036020840152611ca381866119a0565b90508281036040840152610c2081856119a0565b5f60208284031215611cc7575f80fd5b8151801515811461089c575f80fd5b5f82611cf057634e487b7160e01b5f52601260045260245ffd5b500690565b808202811582820484141761089f5761089f611bf856fea26469706673582212207d56f97fb401fd73c22a6ed6081b715565628f205b9ddf7a26fc309bd092e91664736f6c63430008190033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _anchors (bytes): 0x
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000000
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.