Contract
0xf772868578d82d8cd3ba106eb1d4da16a42e8d55
- Address
- 0xf772868578d82d8cd3ba106eb1d4da16a42e8d55
- Kind
- verified contract FinalPhiSupply
- Balance
- 0 vETH
- Nonce
- 1
- Code
- 7,635 bytes codehash 0xf68c71f1ac43800e5dfdcbab5b498f1c11b80116d033ffd72fe7cc9daaed2290
account tree
- Tree
- 1 · accounts
- Present
- no leaf
- Key
- 0x1fedf126d7910fd436a0719e73fbe8cd10bddbb82e8953fd32b61dcce67c63a7
- Live root
- 0xe7eb646dfe4cfe9c975fd970c7c565c8d96e5c1edae4440e5f6a2560325fb328
This address holds no leaf in the account tree. Every Final Wallet — service identities included — has one, so an absent leaf means an ordinary account rather than a wallet.
source verified
- Contract
- FinalPhiSupply exact match · immutables masked
- Compiler
- v0.8.33+commit.64118f21
- Optimizer
- enabled · 200 runs
- EVM version
- prague
- Verified
- 2026-09-07T05:00:52.405Z
- Provenance
- preverify-final-chain (forge artifact, bytecode compared against live code)
contracts/finalchain/FinalCertificate.sol
// SPDX-License-Identifier: BUSL-1.1
// Copyright (c) 2024-2026 Final DeFi
// Licensed under the Business Source License 1.1 (the "License")
//
// Change Date: 2029-01-01
// Change License: GPL-2.0-or-later
//
// @author Final DeFi
// @version 1.0.0
pragma solidity ^0.8.20;
import {FinalChainPrecompiles} from "./FinalChainPrecompiles.sol";
import {FinalChainTime} from "./FinalChainTime.sol";
/**
* @title FinalCertificate
* @notice Reads a Final Certificate (`.fcert`, schema v3) on chain.
*
* @dev Final Chain only — it needs the SHA3-256 precompile, because the schema
* hashes with FIPS-202 SHA3 and the EVM has `keccak256`, which is a different
* function.
*
* ## Why the chain parses this at all
*
* `FinalIdentityRegistry.registerWithCertificate` used to take the TBS bytes
* AND the public keys as separate arguments. It derived `certHash` from the
* bytes, which sounds like verification and is not: nothing compared the keys
* to the certificate, so a registrar could bind any certificate to any keypair.
* The registry would then hold a key the certificate does not contain, and every
* signature that key produced would verify against a certificate that never
* authorised it.
*
* So the keys are read OUT of the certificate. There is one input and no way for
* two arguments to disagree.
*
* ## The SubjectKeyId check
*
* The schema defines `SubjectKeyId` as SHA3-256 of the `PublicKeyBlock`. Having
* parsed the block, this recomputes that digest and compares. The field is
* inside the TBS, so it is covered by the CA's signatures — which makes the
* check a statement about what the CA attested, not merely about internal
* consistency of bytes the caller supplied.
*
* ## What this does NOT do
*
* It does not verify the CA's signatures over the TBS, and it does not walk the
* chain to the root. Both are possible here — the precompiles verify ML-DSA-87
* and SLH-DSA-SHAKE-256s — and both are deliberately out of scope for the
* registry's bootstrap path, where the registrar is the party that issued the
* certificate in the first place. `verifyIssuerSignatures` below is provided for
* callers that need it, and the identity registry uses it once a CA is itself
* registered.
*/
library FinalCertificate {
/// `"PQCF"`.
uint32 internal constant MAGIC = 0x50514346;
/// The current wire generation — v5's `Version = 2` (chain-attested
/// issuance; ruled 2026-09-01). The v4 wire (`Version = 1`) stays
/// PARSEABLE so pre-cutover artifacts still read; encoders write 2.
/// fails to parse rather than being reinterpreted: `pqKeysHash` and every
/// wallet address derive from this exact layout.
uint32 internal constant VERSION = 2;
/// The v4 generation, accepted on parse for pre-cutover artifacts.
uint32 internal constant VERSION_V4 = 1;
/// @notice The 0x0102 Institution identity extension (issuer profile).
uint16 internal constant EXT_INSTITUTION = 0x0102;
/// Algorithm ids ARE the FIPS numbers, in one space for signatures and KEMs
/// — the same ids the quorum wire format and the backend registry use, and
/// the numbers the precompile addresses end in.
/// ML-KEM-1024 (FIPS 203), the lattice half of the encapsulation pair.
uint16 internal constant ALG_ML_KEM_1024 = 0x0003;
/// ML-DSA-87 (FIPS 204). Transaction class.
uint16 internal constant ALG_ML_DSA_87 = 0x0004;
/// SLH-DSA-SHAKE-256s (FIPS 205). Access class, and the seal.
uint16 internal constant ALG_SLH_DSA_SHAKE_256S = 0x0005;
/// FN-DSA (FIPS 206). Reserved: no implementation, never accepted.
uint16 internal constant ALG_FN_DSA = 0x0006;
/// HQC-5 (FIPS 207), the code-based half of the encapsulation pair.
uint16 internal constant ALG_HQC_5 = 0x0007;
/// Certificate signing. Says which key to verify WITH; it grants nothing —
/// that comes from `Depth` and `MaxDelegationDepth`.
uint16 internal constant PURPOSE_CERT_SIGNING = 0x0004;
/// The wallet's four slots, in two stages of two.
///
/// A certificate carries ONE stage, never all four. The stage is what gets
/// issued, rotated and revoked as a unit, and a holder presenting a live
/// certificate presents both of that stage's keys or neither — splitting
/// them per slot would let half a stage be presented as if it were whole.
///
/// This applies to services exactly as it applies to a user's wallet.
/// A co-signer is a Final Wallet: same four slots, same split, same
/// algorithms. There is no second kind of identity in this system.
uint16 internal constant PURPOSE_ACTIVE_TX = 0x0010;
uint16 internal constant PURPOSE_ACTIVE_ACCESS = 0x0011;
uint16 internal constant PURPOSE_RECOVERY_TX = 0x0012;
uint16 internal constant PURPOSE_RECOVERY_ACCESS = 0x0013;
/// @dev v4's encapsulation purposes. Parsed, and each stage's pair is
/// resolved alongside its signing pair — `FinalIdentityRegistry` then
/// stores them so a sender can encapsulate to a registered party
/// without a second lookup somewhere less authoritative.
///
/// They were declared and skipped for one release, which is how the
/// registry's four encapsulation-key mappings ended up read in three
/// places and written in none: `kemCommitments` hashed the empty
/// string for every account and `kemKeysOf` returned nothing.
uint16 internal constant PURPOSE_ACTIVE_KEM = 0x0014;
uint16 internal constant PURPOSE_RECOVERY_KEM = 0x0015;
/// @dev The seal: a second SLH-DSA-SHAKE-256s key, distinct from the access
/// key, that co-signs execution-class quorum decisions. Carried by
/// SERVICE certificates only — a user's wallet never seals — and
/// optional in the schema, so a certificate without it parses
/// unchanged. Outside `keysHash`: a seal is operational, rotated by
/// issuing a new live certificate, and it must not move a wallet
/// address it plays no part in.
uint16 internal constant PURPOSE_ACTIVE_SEAL = 0x0016;
/// @dev A purpose no certificate can carry, so `parse` can be told "this
/// stage has no encapsulation slot" without a second boolean. `0xffff`
/// is outside the registry and reserved by being used here.
uint16 internal constant NO_KEM_PURPOSE = 0xffff;
/// Nanoseconds per second. The schema's validity fields are nanoseconds and
/// `block.timestamp` is seconds; a comparison across the two units is a bug
/// waiting for the first certificate anybody actually checks.
/// @dev The schema stamps validity in NANOseconds and this chain's clock is
/// MILLIseconds, so a certificate converts down by 1e6 rather than by
/// 1e9. It was 1e9 — seconds — which made every `notBefore` look 1000x
/// too small against `block.timestamp` and every certificate
/// permanently "already valid", including one issued for the future.
uint64 internal constant NS_PER_MILLISECOND = FinalChainTime.NS_PER_MILLISECOND;
/// @notice What the chain keeps out of one certificate.
struct Parsed {
bytes32 certHash;
bytes32 serial;
/// keccak256 of the IssuerDN bytes, for the chain-issuer pin: a
/// chain-attested certificate carries the ruled constant DN and the
/// registry compares hashes rather than strings.
bytes32 issuerDnHash;
/// The SubjectDN bytes verbatim — the jurisdiction rule reads its
/// `C=` component at issuer registration.
bytes subjectDn;
/// The 0x0102 Institution extension VALUE, when present; empty
/// otherwise. Issuer registration parses jurisdiction out of it.
bytes institutionExt;
/// SHA3-256 of the ISSUER's public key block. Zero-length — and so
/// `bytes32(0)` here — for exactly one certificate in the hierarchy,
/// which is what terminates chain validation.
bytes32 authorityKeyId;
/// SHA3-256 of this certificate's own public key block. The child's
/// `authorityKeyId` must equal it, which is what links the two.
bytes32 subjectKeyId;
uint8 depth;
uint8 maxDelegationDepth;
/// MILLISECONDS, converted from the schema's nanoseconds — this chain's clock.
uint64 notBefore;
/// Milliseconds. Zero means never expires, which the schema allows.
uint64 notAfter;
/// The stage's transaction-class key. ML-DSA-87 — spending, and every
/// high-cadence protocol action.
bytes transactionKey;
/// The stage's access-class key. SLH-DSA-SHAKE-256s — identity,
/// rotation, recovery-pair promotion. A different hardness assumption,
/// so a lattice break leaves the key that governs identity standing.
bytes accessKey;
/// The stage's ML-KEM-1024 encapsulation key. Empty on a CA, which has
/// no encapsulation stage, and on any v4 certificate issued without
/// one — see `parse` for why that is tolerated rather than refused.
bytes kemMlKem;
/// The stage's HQC-5 encapsulation key. Carried under the SAME purpose
/// as the lattice half and distinguished only by algorithm, which is
/// why the parser matches on the `(purpose, algorithm)` pair.
bytes kemHqc;
/// The service's seal key (`PURPOSE_ACTIVE_SEAL`, SLH-DSA-SHAKE-256s).
/// Empty on every certificate that does not carry one — a user wallet,
/// a recovery stage, a CA.
bytes sealKey;
/// Where the TBS ends, so a caller holding the whole certificate can
/// find the `SignatureBlock` without parsing forward again.
uint256 tbsLength;
}
error BadMagic(uint32 got);
error BadVersion(uint32 got);
error Truncated(uint256 needed, uint256 got);
error SubjectKeyIdMismatch(bytes32 derived, bytes32 declared);
error MissingSlot(uint16 purpose);
error WrongAlgorithmForSlot(uint16 purpose, uint16 algorithm);
error DuplicateKey(uint16 purpose, uint16 algorithm);
error KeysNotSorted();
error BadKeyLength(uint16 algorithm, uint256 length);
error InvalidDepth(uint8 depth, uint8 maxDelegationDepth);
error ValidityInverted(uint64 notBefore, uint64 notAfter);
/**
* @notice Parse and self-check a `TBSCertificate`.
* @param tbs the TBS bytes, verbatim. Not the whole certificate.
* @param txPurpose the transaction-class purpose this stage should carry.
* @param accessPurpose the access-class purpose for the same stage.
*
* @dev Checking for a CAPABILITY rather than a type is the schema's own
* rule, and the reason there is no type field to check instead. Passing the
* LIVE purposes to a recovery certificate finds neither key and reverts —
* which is what stops a recovery certificate being registered as a live one
* and handing the recovery pair everyday authority.
*/
function parse(bytes calldata tbs, uint16 txPurpose, uint16 accessPurpose, uint16 kemPurpose)
internal
view
returns (Parsed memory out)
{
_need(tbs, 58);
if (uint32(bytes4(tbs[0:4])) != MAGIC) revert BadMagic(uint32(bytes4(tbs[0:4])));
// Both live generations. v4 artifacts predate chain-attested issuance
// and still parse — supersession is handled at admission (PoP and the
// chain-issuer pins), not by refusing to read history.
uint32 wireVersion = uint32(bytes4(tbs[4:8]));
if (wireVersion != VERSION && wireVersion != VERSION_V4) revert BadVersion(wireVersion);
out.certHash = FinalChainPrecompiles.sha3_256(tbs);
out.serial = bytes32(tbs[8:40]);
out.depth = uint8(tbs[40]);
out.maxDelegationDepth = uint8(tbs[41]);
uint64 notBeforeNs = uint64(bytes8(tbs[42:50]));
uint64 notAfterNs = uint64(bytes8(tbs[50:58]));
if (out.maxDelegationDepth < out.depth) {
revert InvalidDepth(out.depth, out.maxDelegationDepth);
}
if (notAfterNs != 0 && notAfterNs <= notBeforeNs) {
revert ValidityInverted(notBeforeNs, notAfterNs);
}
out.notBefore = notBeforeNs / NS_PER_MILLISECOND;
out.notAfter = notAfterNs == 0 ? 0 : notAfterNs / NS_PER_MILLISECOND;
// Four length-prefixed fields: IssuerDN, SubjectDN, AuthorityKeyId,
// SubjectKeyId. Every field before them is fixed width, which is the
// whole reason the schema orders them this way.
uint256 p = 58;
uint256 issuerDnLen;
(p, issuerDnLen) = _skipLengthPrefixed(tbs, p);
out.issuerDnHash = keccak256(tbs[p - issuerDnLen:p]);
uint256 subjectDnLen;
(p, subjectDnLen) = _skipLengthPrefixed(tbs, p);
out.subjectDn = tbs[p - subjectDnLen:p];
uint256 akidLen;
(p, akidLen) = _skipLengthPrefixed(tbs, p);
out.authorityKeyId = _bytes32At(tbs, p - akidLen, akidLen);
uint256 skidLen;
(p, skidLen) = _skipLengthPrefixed(tbs, p);
uint256 skidStart = p - skidLen;
_need(tbs, p + 2);
uint16 keyCount = uint16(bytes2(tbs[p:p + 2]));
p += 2;
// AFTER the count word. `SubjectKeyId` is SHA3-256 of the KeyEntry
// array alone — `encodeTbs` writes `PublicKeyCount` as its own field and
// `encodePublicKeyBlock` returns only the entries. Hashing the count in
// produces a digest that is self-consistent and matches no certificate
// any issuer ever wrote.
uint256 blockStart = p;
uint32 previousSort = 0;
for (uint256 i = 0; i < keyCount; i++) {
_need(tbs, p + 8);
uint16 alg = uint16(bytes2(tbs[p:p + 2]));
uint16 purpose = uint16(bytes2(tbs[p + 2:p + 4]));
uint32 keyLen = uint32(bytes4(tbs[p + 4:p + 8]));
p += 8;
_need(tbs, p + keyLen);
// Ascending by (purpose, algorithm), duplicates invalid. The schema
// requires the order so `certHash` is reproducible across
// implementations; enforcing it here also means a second entry for
// one slot cannot quietly shadow the first.
uint32 sortKey = (uint32(purpose) << 16) | uint32(alg);
if (i > 0) {
if (sortKey == previousSort) revert DuplicateKey(purpose, alg);
if (sortKey < previousSort) revert KeysNotSorted();
}
previousSort = sortKey;
// The algorithm is pinned per CLASS, not merely recorded. A
// transaction slot carrying an access-class key would verify
// cryptographically and mean something entirely different — an
// identity key must never authorize a transaction, or splitting the
// classes buys nothing.
// Matched on the PAIR, not on the purpose alone. A CA carries two
// keys under one purpose (`0x0004`) distinguished only by
// algorithm, so matching on purpose first would find the first of
// them twice and the second never.
if (purpose == txPurpose && alg == ALG_ML_DSA_87) {
if (keyLen != FinalChainPrecompiles.ML_DSA_87_PUBLIC_KEY_LEN) {
revert BadKeyLength(alg, keyLen);
}
out.transactionKey = tbs[p:p + keyLen];
} else if (purpose == accessPurpose && alg == ALG_SLH_DSA_SHAKE_256S) {
if (keyLen != FinalChainPrecompiles.SLH_DSA_SHAKE_256S_PUBLIC_KEY_LEN) {
revert BadKeyLength(alg, keyLen);
}
out.accessKey = tbs[p:p + keyLen];
} else if (purpose == kemPurpose && alg == ALG_ML_KEM_1024) {
out.kemMlKem = tbs[p:p + keyLen];
} else if (purpose == kemPurpose && alg == ALG_HQC_5) {
out.kemHqc = tbs[p:p + keyLen];
} else if (purpose == PURPOSE_ACTIVE_SEAL && alg == ALG_SLH_DSA_SHAKE_256S) {
if (keyLen != FinalChainPrecompiles.SLH_DSA_SHAKE_256S_PUBLIC_KEY_LEN) {
revert BadKeyLength(alg, keyLen);
}
out.sealKey = tbs[p:p + keyLen];
} else if (purpose == PURPOSE_ACTIVE_SEAL) {
// The seal is hash-based by definition — it exists to stand on
// the OTHER assumption from the transaction key it co-signs
// with. A lattice seal would be two signatures on one bet.
revert WrongAlgorithmForSlot(purpose, alg);
} else if (purpose == txPurpose || purpose == accessPurpose) {
// A slot the caller asked for, carrying the wrong scheme. It
// would verify cryptographically and mean something else
// entirely — an identity key must never authorize a
// transaction, or splitting the classes buys nothing.
revert WrongAlgorithmForSlot(purpose, alg);
} else if (purpose == kemPurpose) {
// Same rule for the encapsulation slot. A third KEM appearing
// under this purpose is a hybrid whose second family nobody
// agreed on, and admitting it silently is how a pair becomes a
// trio that one reader honours and another ignores.
revert WrongAlgorithmForSlot(purpose, alg);
}
// NO length check on the KEM keys here, and that is deliberate.
// The signing slots are checked against a constant because the
// parser's own callers depend on the length; an encapsulation key
// is checked by `0x0203` / `0x0207` at the moment it is REGISTERED,
// where the answer is a well-formedness verdict rather than a
// parse failure. Two checks of the same thing in two shapes is how
// one of them ends up weaker and nobody notices which.
p += keyLen;
}
// `SubjectKeyId` is SHA3-256 of the KeyEntry array, count word
// EXCLUDED — `blockStart` is taken after the count is consumed, for the
// reason given where it is set. Recomputing it is what turns "these
// bytes decode" into "the CA signed these exact keys"; the field is
// inside the TBS, so it is covered by the signatures.
out.subjectKeyId = FinalChainPrecompiles.sha3_256(tbs[blockStart:p]);
bytes32 declared = _bytes32At(tbs, skidStart, skidLen);
if (out.subjectKeyId != declared) revert SubjectKeyIdMismatch(out.subjectKeyId, declared);
// Both or neither. A stage is issued as a unit, so a certificate
// carrying one of its two keys is not a partial certificate — it is a
// certificate for a stage that does not exist.
if (out.transactionKey.length == 0) revert MissingSlot(txPurpose);
if (out.accessKey.length == 0) revert MissingSlot(accessPurpose);
// The encapsulation pair is both-or-neither for the same reason, and
// the reason is louder here: a hybrid quietly reduced to one family is
// identical on the wire, so a certificate carrying only the lattice
// half would seal successfully and silently drop the code-based hedge.
// Neither is the CA case and the pre-v4 case, both legitimate.
if ((out.kemMlKem.length == 0) != (out.kemHqc.length == 0)) {
revert MissingSlot(kemPurpose);
}
_need(tbs, p + 2);
uint16 extCount = uint16(bytes2(tbs[p:p + 2]));
p += 2;
for (uint256 i = 0; i < extCount; i++) {
_need(tbs, p + 7);
uint16 extType = uint16(bytes2(tbs[p:p + 2]));
uint32 valueLen = uint32(bytes4(tbs[p + 3:p + 7]));
p += 7;
_need(tbs, p + valueLen);
// The Institution extension's VALUE, kept for the issuer
// profile's jurisdiction rule. Everything else is skipped as
// before — extensions are structural to certHash, semantic to
// whichever consumer knows them.
if (extType == EXT_INSTITUTION) out.institutionExt = tbs[p:p + valueLen];
p += valueLen;
}
out.tbsLength = p;
}
/// @notice Parse a LIVE-stage certificate: `activeTransaction` + `activeAccess`.
/// @dev `external`, like the other three entry points below: the registry
/// sits against the EIP-170 ceiling and the TBS parser is its single
/// largest inlined dependency, so the four doors it actually calls are
/// DEPLOY-LINKED — the library is one more contract in the plane's fixed
/// nonce-0 deploy order (doctrine §2 of `arch/final-chain-regenesis.md`),
/// its address baked immutably into the registry's bytecode. A linked
/// library is code, not a key: nothing can repoint it after deployment.
function parseLive(bytes calldata tbs) external view returns (Parsed memory) {
return parse(tbs, PURPOSE_ACTIVE_TX, PURPOSE_ACTIVE_ACCESS, PURPOSE_ACTIVE_KEM);
}
/// @notice Parse a RECOVERY-stage certificate.
/// @dev The recovery pair authorizes rotating the wallet's own credentials
/// and NOTHING else — acting as a guardian, an ordinary action for that
/// account, uses the live access key. Keeping the two stages in separate
/// certificates is what makes that boundary something a verifier can see.
function parseRecovery(bytes calldata tbs) external view returns (Parsed memory) {
return parse(tbs, PURPOSE_RECOVERY_TX, PURPOSE_RECOVERY_ACCESS, PURPOSE_RECOVERY_KEM);
}
/// @notice Parse a CA certificate, whose two keys are both cert-signing.
/// @dev No encapsulation purpose: a CA signs and is never sealed to, so
/// `PURPOSE_ACTIVE_KEM` is passed as a value the loop can never match. A
/// CA certificate carrying encapsulation keys would parse them into slots
/// `_write` then discards, which is a shape worth refusing to have.
function parseCa(bytes calldata tbs) external view returns (Parsed memory) {
return parse(tbs, PURPOSE_CERT_SIGNING, PURPOSE_CERT_SIGNING, NO_KEM_PURPOSE);
}
/**
* @notice Verify a CA's dual signature over `tbs`.
* @dev Both must verify, not either. Two signatures under two different
* hardness assumptions is the entire reason the schema carries two, and
* accepting one would collapse that to whichever family breaks first.
*/
function verifyIssuerSignatures(
bytes memory tbs,
bytes memory issuerMlDsaKey,
bytes memory issuerSlhDsaKey,
bytes memory mlDsaSignature,
bytes memory slhDsaSignature
) external view returns (bool) {
return FinalChainPrecompiles.verifyMlDsa87(issuerMlDsaKey, tbs, mlDsaSignature)
&& FinalChainPrecompiles.verifySlhDsa(issuerSlhDsaKey, tbs, slhDsaSignature);
}
function _need(bytes calldata tbs, uint256 upto) private pure {
if (tbs.length < upto) revert Truncated(upto, tbs.length);
}
function _skipLengthPrefixed(bytes calldata tbs, uint256 p)
private
pure
returns (uint256 next, uint256 length)
{
_need(tbs, p + 4);
length = uint32(bytes4(tbs[p:p + 4]));
next = p + 4 + length;
_need(tbs, next);
}
function _bytes32At(bytes calldata tbs, uint256 start, uint256 length)
private
pure
returns (bytes32)
{
// A SubjectKeyId that is not 32 bytes is not a SHA3-256 digest, so it
// cannot match and the comparison will fail — which is the correct
// outcome and needs no separate error.
if (length != 32) return bytes32(0);
return bytes32(tbs[start:start + 32]);
}
}
contracts/finalchain/FinalChainPrecompiles.sol
// SPDX-License-Identifier: BUSL-1.1
// Copyright (c) 2024-2026 Final DeFi
// Licensed under the Business Source License 1.1 (the "License")
//
// Change Date: 2029-01-01
// Change License: GPL-2.0-or-later
//
// @author Final DeFi
// @version 1.0.0
pragma solidity ^0.8.20;
/**
* @title FinalChainPrecompiles
* @notice The three primitives Final Chain adds to the EVM, and the only
* supported way to reach them.
*
* @dev **These exist ONLY on Final Chain (chain id 48359).** They are provided
* by `final-reth`, the node binary in `FinalBackend/vendor/reth/final/`, and
* nothing at these addresses on Ethereum, Optimism or any other chain will
* answer. A contract that calls them must be one that only ever runs here;
* `assertAvailable` below is the cheap way to fail loudly rather than treat an
* empty return as a verified signature.
*
* The addresses are the FIPS numbers, which is the whole allocation rule —
* there is no local registry to consult and no way for two implementations to
* disagree about where a primitive lives:
*
* | address | primitive | FIPS |
* |---|---|---|
* | `0x…0202` | SHA3-256 | 202 |
* | `0x…0203` | ML-KEM-1024 key validation | 203 |
* | `0x…0204` | ML-DSA-87 verify | 204 |
* | `0x…0205` | SLH-DSA-SHAKE-256s verify | 205 |
* | `0x…0207` | HQC-5 key validation | 207 |
*
* The two KEM addresses VALIDATE keys and do nothing else, for one reason:
* encapsulation is a SENDER operation and decapsulation needs the secret key,
* so neither belongs on a chain at all. Checking that a registered public key
* is well-formed is hardening rather than a dependency, and nothing in this
* system waits on it.
*
* HQC's number is 207. It had none when the KEM pair was chosen, which was the
* one thing separating it from ML-KEM here — a primitive with no standard
* number has no address under this rule, and inventing one would have been a
* local convention masquerading as the global one.
*
* **No AEAD precompile, at any number.** The chain must never be able to
* decrypt an intent, and checking a revealed body against its commitment is a
* hash compare that `0x0202` already serves.
*
* ## Why this library refuses to take a public key from its caller
*
* It does take one — the primitives are pure functions and cannot do otherwise.
* The rule lives one level up, in `FinalPqQuorum`: a key passed as an argument
* proves nothing, because anyone holding a keypair can produce a valid
* signature under it. Only a key read from `FinalIdentityRegistry` is evidence
* about WHO signed. Every call site here must be able to answer "where did this
* key come from" with "storage", never "calldata".
*
* ## `success` is not the answer
*
* A `staticcall` to a verifier returns two things and both matter. `success`
* false means the call was malformed — usually a length bug in the caller — and
* `success` true with a zero word means the signature did not verify. The
* helpers below collapse both to `false` for the caller's convenience, which is
* safe in that direction and only in that direction: treating a failed call as
* a valid signature would be the whole security of the system.
*/
library FinalChainPrecompiles {
/// @notice SHA3-256 (FIPS 202). NOT `keccak256`, which is the
/// pre-standardisation padding and produces a different digest.
address internal constant SHA3_256 = address(0x0202);
/// @notice ML-DSA-87 verification (FIPS 204). Transaction-class keys.
address internal constant ML_DSA_87 = address(0x0204);
/// @notice SLH-DSA-SHAKE-256s verification (FIPS 205). Access-class keys.
address internal constant SLH_DSA_SHAKE_256S = address(0x0205);
/// @notice ML-KEM-1024 encapsulation-key validation (FIPS 203).
/// @dev VALIDATES; it does not encapsulate. Runs FIPS 203 §7.2's own
/// encapsulation-key check — the type check and the modulus check — and
/// nothing else. Encapsulation is a sender operation and decapsulation
/// needs the secret key, so neither belongs on a chain.
address internal constant ML_KEM_1024 = address(0x0203);
/// @notice HQC-5 public-key validation (FIPS 207).
/// @dev Structural only: the length, and the three padding bits the
/// encoding leaves beyond `n = 57637`. HQC has no cheap key-validity
/// predicate and this does not pretend to one.
address internal constant HQC_5 = address(0x0207);
/// @notice ML-DSA-87 public key length. Round-3 Dilithium5 shares it.
uint256 internal constant ML_DSA_87_PUBLIC_KEY_LEN = 2592;
/// @notice ML-DSA-87 signature length. Round-3 Dilithium5 is 4595.
uint256 internal constant ML_DSA_87_SIGNATURE_LEN = 4627;
/// @notice SLH-DSA-SHAKE-256s public key length (`PK.seed ‖ PK.root`).
uint256 internal constant SLH_DSA_SHAKE_256S_PUBLIC_KEY_LEN = 64;
/// @notice SLH-DSA-SHAKE-256s signature length. The `f` set is 49,856.
uint256 internal constant SLH_DSA_SHAKE_256S_SIGNATURE_LEN = 29792;
/// @notice Thrown when a precompile is absent, i.e. this is not Final Chain
/// or the node is stock reth rather than `final-reth`.
error PrecompileUnavailable(address precompile);
/**
* @notice Reverts unless all five precompiles answer.
* @dev Call this from a constructor. A contract whose security rests on PQ
* verification must not deploy onto a chain that cannot perform it — the
* failure mode otherwise is a quorum that reaches threshold with zero valid
* signatures, discovered at the worst possible moment.
*
* The probe is SHA3-256 of the empty string, whose value is a published
* FIPS 202 constant. It cannot be produced by an address with no code
* (which returns empty) nor by `keccak256` (which gives a different digest
* for the same input), so it distinguishes "the right precompile" from both
* "nothing here" and "the wrong hash function".
*/
function assertAvailable() internal view {
bytes32 expected = 0xa7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a;
(bool ok, bytes memory out) = SHA3_256.staticcall("");
if (!ok || out.length != 32 || bytes32(out) != expected) {
revert PrecompileUnavailable(SHA3_256);
}
// The two signature verifiers are probed by shape rather than by a
// known-answer vector: a KAT here would put a 29,792-byte signature in
// this contract's bytecode. A deliberately short input is a
// *precompile error* by contract, so a FAILED call is the pass and a
// silent success would mean something else is answering at the address.
_probeRejectsShortInput(ML_DSA_87);
_probeRejectsShortInput(SLH_DSA_SHAKE_256S);
// The two KEM validators are probed the other way round, because they
// are total by contract: a wrong length is a malformed KEY, which is
// the question being asked, so they ANSWER rather than error. A
// one-byte input must therefore come back as a well-formed `false`, and
// a failed call means nothing is there.
_probeAnswersFalse(ML_KEM_1024);
_probeAnswersFalse(HQC_5);
}
/**
* @dev A short input must make the precompile ERROR. The gas budget is the
* whole subtlety.
*
* A reverting CONTRACT refunds the gas it did not use. A precompile that
* returns an error consumes **everything forwarded to it** — and Solidity
* forwards 63/64 of what is left by default. Two such probes in a
* constructor therefore burn all but 1/4096 of the deployment's gas, and
* the deploy fails with no revert data at all.
*
* That is not hypothetical: it is what happened the first time this ran
* against a real `final-reth`, and no Foundry test could have caught it.
* A mocked precompile is a contract, and a contract's `require` hands the
* gas back.
*
* 5,000 is generous for a call that fails on a length check before any
* cryptography runs, and small enough that both probes together are noise
* against a deployment.
*/
function _probeRejectsShortInput(address precompile) private view {
bool ok;
assembly ("memory-safe") {
let ptr := mload(0x40)
mstore8(ptr, 0x00)
ok := staticcall(5000, precompile, ptr, 0x01, 0x00, 0x00)
}
if (ok) revert PrecompileUnavailable(precompile);
}
/**
* @dev A one-byte input must come back as a well-formed zero word.
*
* The inverse of `_probeRejectsShortInput`, and the inversion is the point:
* these two precompiles are TOTAL. Every byte string has an answer to "is
* this a well-formed key", and for one byte the answer is no. A precompile
* that errored here would be one that treats a malformed key as a caller
* bug, which is the opposite of what a registry wants.
*
* Gas is bounded for the same reason as the other probe — an erroring
* precompile consumes everything forwarded — even though the pass case
* returns normally and refunds.
*/
function _probeAnswersFalse(address precompile) private view {
bool ok;
bytes32 answer;
assembly ("memory-safe") {
let ptr := mload(0x40)
mstore8(ptr, 0x00)
ok := staticcall(5000, precompile, ptr, 0x01, ptr, 0x20)
answer := mload(ptr)
}
if (!ok || answer != bytes32(0)) revert PrecompileUnavailable(precompile);
}
/**
* @notice Is `encapsulationKey` a well-formed ML-KEM-1024 key?
*
* @dev The check a registry owes a sender. A malformed encapsulation key
* stored on chain is an account whose intents cannot be sealed, and the
* discovery happens at the first attempt to seal one — on the hybrid path,
* as a pair silently reduced to one family, which is the failure with no
* error attached.
*
* False rather than reverting on any shape, including the wrong length,
* because the caller is asking a question and every input has an answer.
*/
function isWellFormedMlKem1024(bytes memory encapsulationKey) internal view returns (bool) {
return _validatesKey(ML_KEM_1024, encapsulationKey);
}
/// @notice Is `publicKey` a well-formed HQC-5 key?
/// @dev Structural, and honestly partial — see the precompile. It catches a
/// truncated key, a key from the wrong parameter set, and a tail carrying
/// smuggled bytes, which are the three ways this goes wrong in practice.
function isWellFormedHqc5(bytes memory publicKey) internal view returns (bool) {
return _validatesKey(HQC_5, publicKey);
}
/// @dev A failed CALL is not a false answer. It means nothing is at the
/// address — this is not Final Chain, or the node is stock reth — and
/// reading it as "the key is malformed" would silently disable the check on
/// exactly the deployment where it cannot run.
function _validatesKey(address precompile, bytes memory key) private view returns (bool) {
(bool ok, bytes memory out) = precompile.staticcall(key);
if (!ok || out.length != 32) revert PrecompileUnavailable(precompile);
return bytes32(out) != bytes32(0);
}
/// @notice FIPS 202 SHA3-256 over `data`.
/// @dev The certificate schema hashes `TBSCertificate`, `SubjectKeyId` and
/// `AuthorityKeyId` with this, so it is the only function that can check a
/// `certHash` against the bytes it claims to summarise.
function sha3_256(bytes memory data) internal view returns (bytes32 digest) {
(bool ok, bytes memory out) = SHA3_256.staticcall(data);
if (!ok || out.length != 32) revert PrecompileUnavailable(SHA3_256);
digest = bytes32(out);
}
/// @notice Verify an ML-DSA-87 signature. False on any failure, including
/// a malformed call.
function verifyMlDsa87(bytes memory publicKey, bytes memory message, bytes memory signature)
internal
view
returns (bool)
{
if (
publicKey.length != ML_DSA_87_PUBLIC_KEY_LEN
|| signature.length != ML_DSA_87_SIGNATURE_LEN
) return false;
return _verify(ML_DSA_87, publicKey, signature, message);
}
/// @notice Verify an SLH-DSA-SHAKE-256s signature. False on any failure.
function verifySlhDsa(bytes memory publicKey, bytes memory message, bytes memory signature)
internal
view
returns (bool)
{
if (
publicKey.length != SLH_DSA_SHAKE_256S_PUBLIC_KEY_LEN
|| signature.length != SLH_DSA_SHAKE_256S_SIGNATURE_LEN
) return false;
return _verify(SLH_DSA_SHAKE_256S, publicKey, signature, message);
}
/// @dev `publicKey ‖ signature ‖ message`, in that order. Both fixed-length
/// fields come first so the message is unambiguously the remainder — the
/// same reason the precompile takes no length prefix.
function _verify(
address precompile,
bytes memory publicKey,
bytes memory signature,
bytes memory message
) private view returns (bool) {
(bool ok, bytes memory out) =
precompile.staticcall(abi.encodePacked(publicKey, signature, message));
return ok && out.length == 32 && bytes32(out) != bytes32(0);
}
}
contracts/finalchain/FinalChainTime.sol
// SPDX-License-Identifier: BUSL-1.1
// Copyright (c) 2024-2026 Final DeFi
pragma solidity ^0.8.20;
/**
* @title FinalChainTime
* @notice **On Final Chain, `block.timestamp` is MILLISECONDS.**
*
* @dev Every other EVM chain stamps seconds. This one cannot: it mints a block
* every 100 ms and Ethereum requires block timestamps to strictly increase, so
* a second-denominated clock would run out of distinct values ten times over
* per second. Milliseconds is the deliberate choice, and it is a property of
* the CHAIN — `final-reth` — not of any contract here.
*
* Every duration on this chain is therefore in milliseconds, and this library
* exists so that is stated in one place instead of assumed in fifteen.
*
* ## How this was found, which is the reason for the naming rules below
*
* It was not found by the test suite. Foundry's `block.timestamp` is seconds,
* so all 1249 tests agreed with the contracts and every one of them was wrong
* about the chain they deploy to. It was found the first time anything
* exercised a deadline against the real chain — a posted intent, which reverted
* `DeadlinePassed` against a header whose deadline had been computed from wall
* time.
*
* What was actually broken was worse than a posting. `rotationInitiatedAt` is
* written from `block.timestamp` and compared against `rotationInitiatedAt +
* delaySeconds`: a millisecond clock plus a second-denominated delay. The
* 24-hour default recovery delay elapsed in **86 seconds**, and the two-year
* dormancy threshold in about seventeen hours. That delay is the thing standing
* between a stolen recovery key and an account.
*
* Nothing had noticed because nothing time-dependent had ever run: `walletCount`
* is 0, `FinalBundleLog.size` is 0, and no intent had been posted.
*
* ## The naming rule
*
* A field or constant carrying a duration or an instant on this chain ends in
* `Ms`. Not decoration — the bug was a field named `delaySeconds` that held
* milliseconds, and a name that lies is how the next reader reintroduces it.
* `SECONDS` names are gone from `contracts/finalchain/` and must not come back.
*
* Solidity's `hours` / `days` suffixes are still the clearest way to write a
* duration, so they are written as `24 hours * MS_PER_SECOND` rather than as a
* literal: the intent stays readable and the unit stays explicit.
*/
library FinalChainTime {
/// @notice Milliseconds per second. The whole conversion, named once.
uint64 internal constant MS_PER_SECOND = 1_000;
/// @notice Milliseconds per nanosecond divisor — the certificate schema
/// stamps validity in NANOseconds, so a certificate converts down to this
/// chain's clock rather than up.
uint64 internal constant NS_PER_MILLISECOND = 1_000_000;
/// @notice This chain's clock, stated as a function so a caller reads the
/// unit rather than remembering it.
/// @dev No arithmetic. It exists to make `FinalChainTime.nowMs()` the thing
/// people write, which is self-describing where `block.timestamp` is not.
function nowMs() internal view returns (uint64) {
return uint64(block.timestamp);
}
}
contracts/finalchain/FinalIdentityRegistry.sol
// SPDX-License-Identifier: BUSL-1.1
// Copyright (c) 2024-2026 Final DeFi
// Licensed under the Business Source License 1.1 (the "License")
//
// Change Date: 2029-01-01
// Change License: GPL-2.0-or-later
//
// @author Final DeFi
// @version 1.0.0
pragma solidity ^0.8.20;
import {FinalCertificate} from "./FinalCertificate.sol";
import {FinalChainTime} from "./FinalChainTime.sol";
import {FinalChainPrecompiles} from "./FinalChainPrecompiles.sol";
import {FinalPqQuorum} from "./FinalPqQuorum.sol";
/**
* @title FinalIdentityRegistry
* @notice Who every party in the system IS, on chain, with its certificate.
*
* @dev Final Chain only. Every service, every co-signer, every certificate
* authority and every operator has one record here, and that record carries the
* party's actual public keys — not commitments to them.
*
* ## Why the full key and not a hash
*
* A commitment would be a quarter of the storage and would be enough to *check*
* a key someone hands you. It is not enough to VERIFY A SIGNATURE, because
* verification needs the key itself, and a key that arrives in calldata proves
* nothing: anyone holding a keypair can produce a valid signature under it. A
* quorum built on caller-supplied keys is a quorum of one — whoever built the
* calldata.
*
* So the keys live here in full, `FinalPqQuorum` reads them from storage, and
* "which key is co-signer 3" has exactly one answer. That question previously
* had three: an environment variable, an on-chain roster, and a Secret Manager
* entry, with nothing comparing them. Every configuration failure in this
* program has been those three disagreeing.
*
* ## The certificate is the record, not a pointer to one
*
* `certHash` is `SHA3-256(TBSCertificate)` — the certificate's own identity per
* the v3 schema, and the handle revocation is keyed on. The schema says
* revocation exists "on Final Chain only"; this is that place.
*
`registerWithCertificate` takes the TBS bytes and **reads everything out of
* them**: the digest, the serial, the key identifiers, the depth pair, the
* validity window and both public keys. It takes no key arguments at all.
*
* That is a correction, and the version it replaces is worth naming because it
* looked right. It took the TBS *and* the keys, derived `certHash` from the
* TBS, and never compared the two — so a registrar could bind any certificate
* to any keypair, and the registry would hold a key the certificate does not
* contain. Every signature that key produced would then verify against a
* certificate that never authorised it.
*
* ## The root is the first record on this chain, not a file somewhere
*
* The schema says Final Chain is the only root CA and that "the root is pinned,
* not distributed" — chain validation terminates at Final Chain **by identity**,
* never by finding a self-signed certificate in a local store.
*
* `registerRoot` is that pin, and it is the only entry point that accepts a
* certificate without checking an issuer's signature. It takes a depth-0,
* self-issued certificate from the bootstrap admin, once. Everything after it
* is `registerWithCertificate`, which **verifies the issuer's ML-DSA and
* SLH-DSA signatures on chain, through the precompiles**, against the issuer's
* own registered keys, and checks that the child's `AuthorityKeyId` is the
* issuer's `SubjectKeyId` and that the issuer's depth admits it.
*
* So there is no path by which a key enters this registry unattested. Not
* "a registrar should only register certified keys" — a registrar *cannot*
* register anything else.
*
* ## Roles are a bitmask
*
* One party is legitimately several things — a co-signer that is also a
* publisher, an operator that is also a guardian. A single enum would force
* either duplicate records for one key (two sources of truth about one party)
* or a role hierarchy nobody agrees on. A mask has neither problem, and a
* quorum asks "does this account carry ROLE_X" rather than "is this account an
* X", which is the same distinction the certificate schema draws when it says
* verifiers check for capabilities and never for types.
*
* ## Membership is hybrid-gated
*
* Who is in this registry, and with which roles, is the root of every quorum on
* the chain — so it is the one thing no single key may decide. Once bootstrap
* is sealed, every membership mutation (register, roles, revoke, an LMS key,
* the registrar threshold itself) and every state-plane configuration change
* that routes through {requireRegistrarQuorum} takes a `ROLE_REGISTRAR` quorum
* whose approvals carry BOTH families: the ML-DSA-87 vote and the SLH-DSA
* seal. A lattice break cannot then rewrite the roster, and neither can a
* hash-function break; only both at once.
*
* The bootstrap window is the exception, and it is the only one: while it is
* open the bootstrap admin writes alone, because every roster has to be
* installed by someone before it can install itself.
*
* ## The sender is not the account
*
* Final Chain transactions are type 0x46, signed by ML-DSA-87, and the node
* derives `msg.sender` from the key: `keccak256(0x04 ‖ publicKey)[12:]`. That
* address pays gas and holds no authority. {accountOfSender} binds it to the
* identity whose `activeTransaction` key it derives from, so a `msg.sender`
* gate anywhere on this chain asks {senderHasRole} and resolves to the
* identity — and a key rotation moves the binding rather than the roster.
*/
/// @dev Domain for a stage's encapsulation commitment. Byte-equal to
/// `FinalWalletFactory.DOMAIN_KEM_BUNDLE` and to `DOMAIN_KEM_BUNDLE_PREIMAGE` in
/// the issuer; three derivations of one word, and a mismatch in any of them is a
/// certificate that verifies nowhere.
bytes32 constant DOMAIN_KEM_BUNDLE = keccak256("FINAL_KEM_BUNDLE_v01");
/// @dev Tree 8's leaf domain — byte-equal to
/// `IdentityRootModule.DOMAIN_IDENTITY_LEAF` on every execution chain.
/// Restated rather than imported because the module lives on other chains and
/// there is no import that would make them one value; the cross-contract
/// parity test pins the pair. The `_PQ_` spelling is historical and FROZEN:
/// the premined vanity certificates were mined against this exact constant,
/// and the leaf it derives is the `certHash` inside every wallet's CREATE2
/// derivation.
bytes32 constant DOMAIN_IDENTITY_LEAF = keccak256("FINAL_IDENTITY_LEAF_PQ_v01");
/// @dev D7 (ruled 2026-09-01): ISSUER records project into tree 8 under their
/// own domain — `DOMAIN_ISSUER_LEAF ‖ certHash ‖ version ‖ issuerTreeRoot` —
/// so an issuer is stapleable for offline licence verification while the
/// distinct domain keeps its leaf out of wallet admission (the gateway folds
/// with the wallet domain, so an issuer leaf can never satisfy
/// `verifyIdentityCert`). `issuerTreeRoot` is a RESERVED word, zero until an
/// issuer's own certificate-tree anchor is wired — the only clean path to
/// offline licence revocation, since the fixed-depth insertion-ordered state
/// trees cannot prove non-inclusion.
bytes32 constant DOMAIN_ISSUER_LEAF = keccak256("FINAL_ISSUER_LEAF_v01");
/// @dev Chain-issuer constants (ruled 2026-09-01, amended same day: C-less).
/// The chain is the issuer but holds no keypair, so every chain-attested
/// certificate carries these two NAMED values in its issuer fields — required
/// by the wire format, verifying nothing, covered by `certHash`. The DN is
/// deliberately env-agnostic AND jurisdiction-silent: the issuer is the
/// worldwide network, not a legal entity, and an env-specific DN would fork
/// `certHash` per environment. Reference implementation:
/// `dashboard/public/fcert.js` (`CHAIN_ISSUER_DN`, `CHAIN_AUTHORITY_KEY_ID`);
/// `docs/developers/certificate-schema.md` § Chain-issuer constants.
bytes32 constant CHAIN_ISSUER_DN_HASH = keccak256("CN=Final Chain,O=Final DeFi");
/// @dev `SHA3-256(utf8("FINAL_CHAIN_AUTHORITY_v01"))` — a DOMAIN constant, not
/// a key digest (the chain has no PublicKeyBlock). Precomputed because the
/// mock SHA3 precompile under Foundry is deliberately not the real function;
/// pinned against `hashlib.sha3_256` and the dashboard's value by test.
/// Zero-length AuthorityKeyId stays reserved for the retired genesis root
/// alone and is admitted nowhere.
bytes32 constant CHAIN_AUTHORITY_KEY_ID =
0x9a6a5d8139ad2d28957698330aaa691017dba7dc80eb7cbec585239fb680bbab;
/// @notice The identity tree's projection door on `FinalStateTrees`. A narrow
/// interface rather than an import, because the trees contract imports this
/// file — the dependency runs that way and this is the one call that runs the
/// other. Same pattern as `IChainSource` on the trees side.
interface IIdentityLeafSink {
function syncIdentityLeaves(address[] calldata accounts) external;
}
/// @notice `FinalRevocationLog`'s recording door, same narrow-interface
/// reasoning. `recorded` is read first so a fingerprint someone already
/// recorded permissionlessly cannot revert the registry mutation feeding it.
interface IRevocationRecorder {
function record(bytes32 signerId) external;
function recorded(bytes32 signerId) external view returns (bool);
}
contract FinalIdentityRegistry {
// ---------------------------------------------------------------- roles
/// @notice May co-sign account-state rounds (tree 1).
uint256 public constant ROLE_ACCOUNT_COSIGNER = 1 << 0;
/// @notice May co-sign MMR / bundle-log advances.
uint256 public constant ROLE_MMR_COSIGNER = 1 << 1;
/// @notice May publish PHI ledger state (tree 2).
uint256 public constant ROLE_PHI_PUBLISHER = 1 << 2;
/// @notice May publish vAsset state (tree 3).
uint256 public constant ROLE_VASSET_PUBLISHER = 1 << 3;
/// @notice May publish oracle data (tree 4).
uint256 public constant ROLE_ORACLE_PUBLISHER = 1 << 4;
/// @notice May publish settlement / asset registry roots (trees 5 and 6).
uint256 public constant ROLE_REGISTRY_PUBLISHER = 1 << 5;
/// @notice May act as a wallet guardian.
uint256 public constant ROLE_GUARDIAN = 1 << 6;
/// @notice May submit transactions on behalf of the protocol.
uint256 public constant ROLE_RELAYER = 1 << 7;
/// @notice May register and revoke identities once bootstrap is sealed.
uint256 public constant ROLE_REGISTRAR = 1 << 8;
/// @notice A certificate authority — the root, or an intermediate under it.
uint256 public constant ROLE_CERTIFICATE_AUTHORITY = 1 << 9;
/// @notice May co-sign `FinalSettlementLog` appends — the cross-chain
/// settlement quorum, the same members whose LMS keys satisfy the
/// execution chains' settlement set. A role of its own rather than a
/// second use of `ROLE_REGISTRY_PUBLISHER`: the registries (trees 5/6)
/// change on listing cadence and settlement leaves release custody, and
/// one role for both would put the value plane behind the listing roster.
uint256 public constant ROLE_SETTLEMENT_COSIGNER = 1 << 10;
// ----------------------------------------------------- action domains
/// @dev One per membership mutation, so an approval to grant a role can
/// never be replayed as one to revoke. The registry is its own verifying
/// contract for these.
bytes32 public constant DOMAIN_REGISTER_WALLET = keccak256("FINAL_REGISTRY_REGISTER_WALLET_v01");
bytes32 public constant DOMAIN_REGISTER_ISSUER = keccak256("FINAL_REGISTRY_REGISTER_ISSUER_v01");
/// @notice The admission proof-of-possession digest domain (schema §v5).
/// The HOLDER signs `keccak256(abi.encode(domain, chainid, registry,
/// certHash, recoveryCertHash, gateNonce))` with the live transaction key
/// (ML-DSA-87) AND the live access key (SLH-DSA-SHAKE-256s) — both
/// families, in the admission transaction, verified by the precompiles.
/// Possession lives in the TRANSACTION, never in the artifact.
bytes32 public constant DOMAIN_IDENTITY_ADMISSION = keccak256("FINAL_IDENTITY_ADMISSION_v01");
/// @notice Root-plane global certificate revocation (D5).
bytes32 public constant DOMAIN_REVOKE_CERTIFICATE =
keccak256("FINAL_REGISTRY_REVOKE_CERTIFICATE_v01");
/// @notice The ISSUING identity's certificate-revocation digest domain.
bytes32 public constant DOMAIN_ISSUER_CERT_REVOCATION =
keccak256("FINAL_ISSUER_CERT_REVOCATION_v01");
bytes32 public constant DOMAIN_REGISTER_LMS_KEY = keccak256("FINAL_REGISTRY_REGISTER_LMS_KEY_v01");
bytes32 public constant DOMAIN_SET_ROLES = keccak256("FINAL_REGISTRY_SET_ROLES_v01");
bytes32 public constant DOMAIN_REVOKE = keccak256("FINAL_REGISTRY_REVOKE_v01");
bytes32 public constant DOMAIN_SET_REGISTRAR_THRESHOLD =
keccak256("FINAL_REGISTRY_SET_REGISTRAR_THRESHOLD_v01");
/// @dev The algorithm id the sender derivation is domain-separated by:
/// ML-DSA-87, FIPS 204, the only algorithm the transaction envelope admits.
uint8 private constant ENVELOPE_ALG_ML_DSA_87 = 4;
// ------------------------------------------------------------- storage
/**
* @notice One party's on-chain identity.
* @dev `version` increments on every mutation and is what a rotation is:
* the record is replaced, not appended to, and the version is how a reader
* on another chain knows which of two copies it saw is newer.
*/
struct Identity {
/// SHA3-256 of the LIVE certificate's TBS bytes. The revocation handle.
bytes32 certHash;
/// SHA3-256 of the RECOVERY certificate's TBS bytes.
bytes32 recoveryCertHash;
/// The certificate's 32-byte serial, `16 B entropy ‖ 16 B counter`.
bytes32 serial;
/// SHA3-256 of this certificate's public key block. A child names it in
/// its own `AuthorityKeyId`, which is how the chain links the two.
bytes32 subjectKeyId;
/// Capability bitmask. Zero for a registered-but-idle party.
uint256 roles;
/// Position on the delegation axis; 0 is the Final Chain root.
uint8 depth;
/// Deepest level this key may issue to. `== depth` means it signs no
/// certificates at all, which is every end entity.
uint8 maxDelegationDepth;
/// Seconds since epoch. The schema's TBS is nanoseconds; the conversion
/// happens off chain because block timestamps are seconds and a
/// comparison across units is a bug waiting for a leap.
/// @dev MILLISECONDS — this chain's clock. See `FinalChainTime`.
uint64 notBefore;
/// Seconds since epoch, or 0 for "never expires" — which the schema
/// allows and personal identity certificates use.
uint64 notAfter;
/// Monotonic. A rotation that does not advance it is refused.
uint64 version;
/// Set by `revoke`. Never unset: a revoked certificate is finished, and
/// an un-revoke would make every past verification re-openable.
bool revoked;
/// Distinguishes "no record" from "a record whose fields are all zero".
bool registered;
}
/**
* @notice A hash-based (LMS) signing key held by a registered account.
*
* The protocol plane's quorums verify LMS, not ML-DSA: an execution chain
* has no PQ precompiles, so `FinalRootAuthority` checks a keccak hash loop
* instead (`arch/hash-based-authority.md`). Those keys are the authority
* over `masterRoot`, and therefore over PQ execution — which makes "who
* holds signer 0x39bb…?" a question the state plane has to be able to
* answer, exactly as it answers it for every other key.
*
* Recorded against an account that is ALREADY registered, so an LMS key is
* a capability of a known identity rather than a standalone credential. It
* inherits that identity's revocation: a revoked account's signer is a
* revoked signer, with nothing extra to remember to do.
*/
struct LmsKey {
/// `I`, hashed into every step of the signature.
bytes16 keyId;
/// Merkle tree height. Bound into the fingerprint, because the leaf
/// commits to node `2^h + q` and a signer who could vary it could vary
/// the numbering.
uint8 height;
/// `T[1]`, the LMS public key.
bytes32 root;
/// Monotonic. A rotation that does not advance it is refused, so a
/// replayed registration cannot reinstate a superseded key.
uint64 version;
/// Distinguishes "no key" from "a key whose fields are all zero".
bool registered;
}
/// @notice The LMS signing key for an account, if it holds one.
/// @dev One slot per (account, chain) — LMS-01. `nextLeaf` on an
/// authority is a complete single-use counter only while the key it names
/// signs for ONE chain, so the roster is stored the way it is armed:
/// the same operator is a different signer on every chain.
mapping(address account => mapping(uint64 chainId => LmsKey)) private _lmsKey;
/// @notice Which account a signer fingerprint belongs to. This is the
/// lookup the whole record exists for: a gateway roster names fingerprints
/// and nothing else, so without it the keys are unattributable.
/// @dev What a fingerprint is bound to: the account that holds it and the
/// chain it signs for — one slot, written once at registration and left in
/// place when superseded (attribution is history). The chain names the
/// (account, chain) slot `lmsSignerIsLive` resolves against.
// NOTE: this contract sits ~13 bytes under EIP-170 (24,563 of 24,576 at
// the pinned optimizer settings). The next feature here pays for itself
// in bytecode first — see the LMS-binding merge and the off-chain
// zero-chain check for what that looks like.
struct LmsBinding {
address account;
uint64 chainId;
}
mapping(bytes32 signerId => LmsBinding) private _lmsBinding;
/// @notice The identity record for an account.
mapping(address account => Identity) private _identity;
/// The four slots, verbatim. All four are stored in full because the
/// precompiles verify against a KEY, not a commitment — and a key that
/// arrived in calldata proves nothing about who signed.
///
/// A CA has two keys, not four, and they live in the two ACTIVE slots. One
/// storage shape rather than two, because every reader would otherwise have
/// to know which kind of party it was looking at before it could look.
mapping(address account => bytes) private _activeTransactionKey;
mapping(address account => bytes) private _activeAccessKey;
mapping(address account => bytes) private _recoveryTransactionKey;
mapping(address account => bytes) private _recoveryAccessKey;
/// @notice The seal key — a service's second SLH-DSA-SHAKE-256s key, which
/// co-signs execution-class quorum decisions. Empty for every identity
/// whose certificate carries no `PURPOSE_ACTIVE_SEAL` entry: users, CAs.
mapping(address account => bytes) private _activeSealKey;
/// @notice Encapsulation keys, per stage. Two algorithms each — ML-KEM-1024
/// (lattice) and HQC-5 (code-based) — so a break in either family leaves the
/// other standing, the same reasoning that pairs ML-DSA with SLH-DSA above.
/// @dev Stored as the RAW keys, like the signing keys, because a registry
/// that held only commitments could not answer "encapsulate to this party"
/// without a second lookup somewhere less authoritative.
mapping(address account => bytes) private _activeKemMlKem;
mapping(address account => bytes) private _activeKemHqc;
mapping(address account => bytes) private _recoveryKemMlKem;
mapping(address account => bytes) private _recoveryKemHqc;
/// @notice Reverse index. A certificate identifies exactly one account, so
/// presenting a `certHash` is enough to find who it belongs to.
mapping(bytes32 certHash => address account) public accountOfCertificate;
/// @notice Revocation by certificate, independent of the account record.
/// A certificate stays revoked even if its account is later re-registered
/// under a new one.
mapping(bytes32 certHash => bool) public certificateRevoked;
/// @notice Who revoked a certificate through the ISSUER half of the lane.
/// Scoped by the verifier: the entry binds only when the recorded revoker
/// is the certificate's own issuer. Never gates registration.
mapping(bytes32 certHash => address) public certificateRevokedBy;
/// @notice Every registered account, in registration order. Small by
/// construction — this is services and co-signers, not wallets.
address[] private _accounts;
/// @notice Bootstrap authority. Zero once `sealBootstrap` has run.
address public bootstrapAdmin;
/// @notice Whether registration still accepts the bootstrap admin.
bool public bootstrapSealed;
/// @notice Where identity mutations project the tree-8 leaf, same-tx.
/// Zero only before {wireStatePlane} — the deploy tooling wires it before
/// the first registration, and the projection is skipped while unset so
/// the wiring transaction itself can be ordered freely in the bootstrap
/// window.
address public stateTrees;
/// @notice Where the PERMANENT standing losses — revocation and LMS-key
/// supersession — are recorded, same-tx. Zero only before {wireStatePlane}.
address public revocationLog;
/// @notice Sealed `ROLE_REGISTRAR` approvals a membership mutation needs.
/// @dev Zero until set, and bootstrap cannot be sealed while it is zero or
/// unreachable: a registry sealed behind a threshold nobody can meet is a
/// registry nobody can ever write to again.
uint256 public registrarThreshold;
/// @notice Replay counter per verifying contract — this registry for its
/// own mutations, each state-plane contract for its configuration. Bound
/// into every registrar digest, so an approval is for exactly one action.
mapping(address caller => uint64) private _gateNonce;
/// @notice The identity a Final Chain sender belongs to. See the contract
/// notes: a sender is derived from the `activeTransaction` key and is not
/// the account.
mapping(address sender => address account) public accountOfSender;
// -------------------------------------------------------------- events
event IdentityRegistered(
address indexed account, bytes32 indexed certHash, uint256 roles, uint64 version
);
event IdentityRolesChanged(address indexed account, uint256 previousRoles, uint256 newRoles);
event LmsKeyRegistered(
address indexed account,
bytes32 indexed signerId,
uint64 indexed chainId,
bytes16 keyId,
uint8 height,
bytes32 root,
uint64 version
);
event IdentityRevoked(address indexed account, bytes32 indexed certHash);
/// @notice One revocation-lane entry: `revoker` is `address(0)` for the
/// root plane, the issuing identity otherwise.
event CertificateRevoked(bytes32 indexed certHash, address indexed revoker);
event BootstrapSealed(address indexed sealedBy);
/// @notice The one-shot state-plane wiring landed.
event StatePlaneWired(address stateTrees, address revocationLog);
event RegistrarThresholdSet(uint256 threshold);
/// @notice A registrar quorum authorized an action. `nonce` is the value
/// the approvals were made over; the next action needs the next one.
event RegistrarQuorumApproved(
address indexed verifyingContract, bytes32 indexed actionDomain, uint64 nonce, uint256 valid
);
// -------------------------------------------------------------- errors
error NotAuthorized(address caller);
error BootstrapAlreadySealed();
error UnknownAccount(address account);
/// @notice A certificate's encapsulation key failed the chain's own
/// well-formedness check. Names the algorithm, because the pair is stored
/// together and "one of these two" is not an actionable answer.
error MalformedEncapsulationKey(address account, uint16 algorithmId);
error CertificateAlreadyBound(bytes32 certHash, address boundTo);
error CertificateIsRevoked(bytes32 certHash);
error VersionNotNewer(uint64 current, uint64 offered);
error IssuerNotACertificateAuthority(address issuer);
error IssuerMayNotSign(address issuer, uint8 depth, uint8 maxDelegationDepth);
error WrongDepth(uint8 got, uint8 want);
error DelegationWidened(uint8 child, uint8 issuer);
error AuthorityKeyIdMismatch(bytes32 got, bytes32 want);
error StagesDisagree(bytes32 liveSerial, bytes32 recoverySerial);
/// @notice `height` outside 1..24. See `FinalLms.MAX_HEIGHT`.
error LmsHeightOutOfRange(uint8 height);
/// @notice A zero root commits to no tree.
error LmsRootIsZero();
/// @notice This fingerprint already belongs to a different account.
error LmsKeyAlreadyBound(bytes32 signerId, address boundTo);
/// @notice Two identities cannot share a transaction key: the sender it
/// derives would be attributable to both.
error SenderAlreadyBound(address sender, address boundTo);
/// @notice Fewer registrars able to seal than the threshold asks for.
error RegistrarThresholdUnreachable(uint256 sealable, uint256 threshold);
error RegistrarThresholdIsZero();
/// @notice {wireStatePlane} ran already, or was handed a zero address.
error StatePlaneAlreadyWired();
error ZeroStatePlane();
/// @notice The holder's admission proof of possession did not verify —
/// one family failed, or the digest was built over the wrong nonce.
error AdmissionProofInvalid(address account);
/// @notice The certificate does not carry the ruled chain-issuer
/// AuthorityKeyId — it is not a chain-attested certificate.
error NotChainAttested(bytes32 authorityKeyId);
/// @notice The certificate's IssuerDN is not the ruled constant.
error WrongIssuerDn(bytes32 issuerDnHash);
/// @notice A chain-attested end entity sits at depth 1 with
/// `maxDelegationDepth == depth`; anything else is not an end entity.
error NotAnEndEntity(uint8 depth, uint8 maxDelegationDepth);
/// @notice An issuer that cannot sign is an end entity wearing a profile.
error IssuerCannotSign(uint8 depth, uint8 maxDelegationDepth);
/// @notice Third-party issuers carry a real `NotAfter` (ruling 3) —
/// expiry is the passive half of their lifecycle.
error IssuerMustExpire();
/// @notice An issuer validity window past the ~2-year ceiling (ruling 3).
error IssuerValidityTooLong(uint64 notBefore, uint64 notAfter);
/// @notice An institution registration without a real ISO 3166 `C=` in
/// its subject DN, or with a jurisdiction that does not match its
/// Institution extension. Only the trust root is jurisdiction-silent.
error JurisdictionMissing();
error JurisdictionMismatch();
// --------------------------------------------------------- constructor
/**
* @param admin The bootstrap registrar. Genesis names the chain deployer.
* @dev The precompile probe is the point of the constructor. This contract
* is meaningless on a chain that cannot verify PQ signatures, and deploying
* it there would produce a registry full of keys nothing can check.
*/
constructor(address admin) {
FinalChainPrecompiles.assertAvailable();
bootstrapAdmin = admin;
}
// ----------------------------------------------------------- authority
/**
* @dev Bootstrap is a real window, not a formality: every roster in this
* system has to be installed by someone before it can install itself, and
* pretending otherwise produced the one roster that could not be
* bootstrapped in `FinalRootAuthority`. It is closed by
* `sealBootstrap`, which is irreversible.
*
* While it is open the admin writes alone. Once it is closed there is no
* single-caller path left — not for a registrar, not for anyone — and
* every mutation goes through the sealed registrar quorum.
*/
function _requireMembershipAuthority(
bytes32 actionDomain,
bytes32 payloadDigest,
uint64 anchorBlock,
FinalPqQuorum.Approval[] calldata approvals
) private {
if (!bootstrapSealed && msg.sender == bootstrapAdmin) return;
_requireRegistrarQuorum(address(this), actionDomain, payloadDigest, anchorBlock, approvals);
}
/**
* @notice The sealed registrar quorum, for the other state-plane contracts.
* @dev `msg.sender` — the calling contract — is the verifying contract the
* digest binds and the counter it burns, so an approval collected for the
* trees' configuration cannot be spent on the bundle log's. The caller
* decides its own bootstrap exemption before calling; this function knows
* no caller's admin and applies none.
*
* Anyone may SUBMIT such a transaction. Authority is the approvals, not the
* sender, which is the whole point of the quorum.
*/
function requireRegistrarQuorum(
bytes32 actionDomain,
bytes32 payloadDigest,
uint64 anchorBlock,
FinalPqQuorum.Approval[] calldata approvals
) external {
_requireRegistrarQuorum(msg.sender, actionDomain, payloadDigest, anchorBlock, approvals);
}
/// @dev The digest is `FinalPqQuorum.digest(verifyingContract, actionDomain,
/// anchorBlock, keccak256(abi.encode(nonce, payloadDigest)))`; the seal is
/// required — membership is the hybrid class.
function _requireRegistrarQuorum(
address verifyingContract,
bytes32 actionDomain,
bytes32 payloadDigest,
uint64 anchorBlock,
FinalPqQuorum.Approval[] calldata approvals
) private {
if (registrarThreshold == 0) revert RegistrarThresholdIsZero();
uint64 nonce = _gateNonce[verifyingContract];
_gateNonce[verifyingContract] = nonce + 1;
bytes32 quorumDigest = FinalPqQuorum.digest(
verifyingContract, actionDomain, anchorBlock, keccak256(abi.encode(nonce, payloadDigest))
);
uint256 valid = FinalPqQuorum.require_(
this,
approvals,
quorumDigest,
ROLE_REGISTRAR,
registrarThreshold,
FinalPqQuorum.ALG_ML_DSA_87,
anchorBlock,
true
);
emit RegistrarQuorumApproved(verifyingContract, actionDomain, nonce, valid);
}
/**
* @notice Set how many sealed registrar approvals a membership mutation needs.
* @dev Bootstrap admin while the window is open; the current registrar
* quorum afterwards, so a registrar set that grows or shrinks can move it.
* Refuses a threshold the sealable registrars cannot meet, and refuses zero:
* both are a registry that can never be written to again.
*/
function setRegistrarThreshold(
uint256 threshold,
uint64 anchorBlock,
FinalPqQuorum.Approval[] calldata approvals
) external {
_requireMembershipAuthority(
DOMAIN_SET_REGISTRAR_THRESHOLD, keccak256(abi.encode(threshold)), anchorBlock, approvals
);
if (threshold == 0) revert RegistrarThresholdIsZero();
uint256 sealable = sealableMemberCount(ROLE_REGISTRAR);
if (sealable < threshold) revert RegistrarThresholdUnreachable(sealable, threshold);
registrarThreshold = threshold;
emit RegistrarThresholdSet(threshold);
}
/// @notice The replay counter the next registrar approval for `caller`
/// must be made over.
function gateNonceOf(address caller) external view returns (uint64) {
return _gateNonce[caller];
}
// -------------------------------------------------------- LMS signers
/**
* @notice The roster identity of an LMS public key.
* @dev Byte-identical to `FinalRootAuthority.signerId`. Restated rather
* than imported because the two live on different chains and there is no
* import that would make them one value — which is precisely why a test
* pins them together. A drift here would make every lookup miss while
* looking perfectly well-formed.
*/
function lmsSignerId(bytes16 keyId, uint8 height, bytes32 root) public pure returns (bytes32) {
return keccak256(abi.encode(keyId, height, root));
}
/**
* @notice Record the LMS signing key an already-registered account holds.
* @dev Membership-gated, same as every other write here.
*
* Deliberately NOT a certificate: an LMS key is a capability of an existing
* identity, not an identity of its own. Binding it to an account means it
* inherits that account's revocation, so retiring a compromised operator is
* one action rather than one-per-key-they-hold.
*
* @param account Must already be registered and not revoked.
* @param version Strictly increasing. A rotation that does not advance it
* is refused, so a replayed registration cannot reinstate a key the
* operator has moved off.
* @param anchorBlock The block the registrars read the roster at; see
* `FinalPqQuorum`. Ignored while bootstrap is open.
* @param approvals The sealed registrar quorum. Empty while bootstrap is open.
*/
function registerLmsKey(
address account,
uint64 chainId,
bytes16 keyId,
uint8 height,
bytes32 root,
uint64 version,
uint64 anchorBlock,
FinalPqQuorum.Approval[] calldata approvals
) external {
_requireMembershipAuthority(
DOMAIN_REGISTER_LMS_KEY,
keccak256(abi.encode(account, chainId, keyId, height, root, version)),
anchorBlock,
approvals
);
Identity storage id = _identity[account];
if (!id.registered) revert UnknownAccount(account);
if (id.revoked) revert CertificateIsRevoked(id.certHash);
// A zero chain id is a tooling mistake, not an attack: the slot it
// would occupy is self-consistent and no authority consults it. The
// publisher refuses it; EIP-170 pressure keeps the check off-chain.
if (height == 0 || height > 24) revert LmsHeightOutOfRange(height);
if (root == bytes32(0)) revert LmsRootIsZero();
// Version lineage is PER (account, chain) — LMS-01 made the same
// operator a different signer on every chain, so chain B starting at
// version 1 says nothing about chain A being at version 3.
LmsKey storage existing = _lmsKey[account][chainId];
// An empty slot holds version 0, so this alone also refuses a version-0
// registration — versions start at 1.
if (version <= existing.version) {
revert VersionNotNewer(existing.version, version);
}
bytes32 signerId = lmsSignerId(keyId, height, root);
address boundTo = _lmsBinding[signerId].account;
if (boundTo != address(0) && boundTo != account) {
revert LmsKeyAlreadyBound(signerId, boundTo);
}
// The fingerprint being superseded, captured before the slot moves —
// `existing` is a storage pointer and reads the NEW key afterwards.
bytes32 superseded = existing.registered
? lmsSignerId(existing.keyId, existing.height, existing.root)
: bytes32(0);
// The superseded fingerprint is left bound to this account rather than
// cleared. It is history: a signature made under the old key was made
// by this operator, and a lookup that stopped resolving would make that
// unprovable after the fact.
_lmsKey[account][chainId] = LmsKey(keyId, height, root, version, true);
_lmsBinding[signerId] = LmsBinding(account, chainId);
emit LmsKeyRegistered(account, signerId, chainId, keyId, height, root, version);
// Supersession is a PERMANENT transition — the old fingerprint stops
// being this slot's current key and nothing re-registers it (a
// re-registration of the same material is the same fingerprint, which
// the guard below leaves alone). Recorded same-tx so the execution
// chains' suspension lane never depends on someone noticing.
if (superseded != bytes32(0) && superseded != signerId) {
_recordRevokedSigner(superseded);
}
_projectIdentity(account);
}
/// @notice The LMS key an account holds for one chain, if any.
function lmsKeyOf(address account, uint64 chainId) external view returns (LmsKey memory) {
return _lmsKey[account][chainId];
}
/// @notice What a fingerprint is bound to: the account that registered it
/// and the chain it signs for. Zeroes for a fingerprint never registered.
/// @dev The revocation log's permanence gate reads this to find the
/// (account, chain) SLOT a fingerprint belongs to — the slot's current key
/// is what separates a superseded fingerprint (permanent, recordable) from
/// a merely lapsed one (expiry, temporary, refused). Attribution is
/// history: the binding survives supersession, exactly as the mapping
/// behind {lmsSignerIsLive} does, because it IS that mapping.
function lmsBindingOf(bytes32 signerId) external view returns (address account, uint64 chainId) {
LmsBinding storage binding = _lmsBinding[signerId];
return (binding.account, binding.chainId);
}
/**
* @notice Is this signer fingerprint held by a live, unrevoked account?
* @dev The question a verifier actually has. A gateway roster names
* fingerprints and nothing else, so "is 0x39bb… still good?" is otherwise
* unanswerable from the state plane.
*/
function lmsSignerIsLive(bytes32 signerId) external view returns (bool live, address account) {
LmsBinding storage binding = _lmsBinding[signerId];
account = binding.account;
if (account == address(0)) return (false, address(0));
// `isActive`, not a registered/revoked pair spelled out here. The
// certificate validity window is part of standing: an expired identity
// already holds no role, and a signer lookup that disagreed would leave
// a roster satisfiable by an operator the rest of the registry has
// stopped honouring. Spelling the condition out a second time is how
// the two drift apart.
if (!isActive(account)) return (false, account);
// The CURRENT key of the fingerprint's own (account, chain) slot, not
// merely one this account ever held: a superseded fingerprint stays
// attributable but stops being live, and a rotation on one chain says
// nothing about the same operator's key on another.
LmsKey storage k = _lmsKey[account][binding.chainId];
live = k.registered && lmsSignerId(k.keyId, k.height, k.root) == signerId;
}
/// @notice Close the bootstrap window. Irreversible.
/// @dev Refuses while the registrar quorum is unset or unreachable, because
/// sealing then would leave a registry nobody can ever write to again. The
/// count is of registrars that can SEAL — a certificate authority carrying
/// the role has no seal key and can never contribute an approval.
function sealBootstrap() external {
if (msg.sender != bootstrapAdmin) revert NotAuthorized(msg.sender);
if (bootstrapSealed) revert BootstrapAlreadySealed();
if (registrarThreshold == 0) revert RegistrarThresholdIsZero();
uint256 sealable = sealableMemberCount(ROLE_REGISTRAR);
if (sealable < registrarThreshold) {
revert RegistrarThresholdUnreachable(sealable, registrarThreshold);
}
bootstrapSealed = true;
bootstrapAdmin = address(0);
emit BootstrapSealed(msg.sender);
}
// ------------------------------------------------- state-plane wiring
/**
* @notice Wire the trees and the revocation log, once, inside the
* bootstrap window.
* @dev One-shot because both pointers are TRUST TOPOLOGY: the trees
* pointer decides where the wallet-creation admission set is written, and
* the log pointer decides where permanent standing losses are recorded. A
* re-wireable pointer would be a key over both. It cannot be a constructor
* argument — both contracts take THIS registry as one — so the deploy
* tooling calls it in the same nonce-fixed block that deploys them, before
* any identity is registered.
*/
function wireStatePlane(address stateTrees_, address revocationLog_) external {
if (bootstrapSealed || msg.sender != bootstrapAdmin) revert NotAuthorized(msg.sender);
if (stateTrees != address(0) || revocationLog != address(0)) revert StatePlaneAlreadyWired();
if (stateTrees_ == address(0) || revocationLog_ == address(0)) revert ZeroStatePlane();
stateTrees = stateTrees_;
revocationLog = revocationLog_;
emit StatePlaneWired(stateTrees_, revocationLog_);
}
/// @dev Project `account`'s tree-8 leaf, same-tx. Skipped while the plane
/// is unwired — the bootstrap-window state the deploy tooling closes
/// before the first registration — and never otherwise: the leaf value is
/// derived by the trees contract from THIS registry's post-mutation state,
/// so there is nothing here to get wrong besides forgetting to call it.
function _projectIdentity(address account) private {
address trees = stateTrees;
if (trees == address(0)) return;
address[] memory one = new address[](1);
one[0] = account;
IIdentityLeafSink(trees).syncIdentityLeaves(one);
}
/// @dev Record a PERMANENTLY retired fingerprint, same-tx, unless the log
/// is unwired or someone already recorded it permissionlessly.
function _recordRevokedSigner(bytes32 signerId) private {
address log = revocationLog;
if (log == address(0)) return;
if (IRevocationRecorder(log).recorded(signerId)) return;
IRevocationRecorder(log).record(signerId);
}
// -------------------------------------------------------- registration
/// @notice The holder's admission proof of possession: both live-stage
/// families over the admission digest (schema §v5). There is no root
/// keypair and no CA signature any more — the chain admits, and the
/// "2 signatures at creation" are the HOLDER's, verified by the
/// precompiles inside this very transaction.
struct AdmissionProof {
bytes mlDsaSignature;
bytes slhDsaSignature;
}
/**
* @notice Register or rotate a Final Wallet identity from its two public
* certificates — CHAIN-ATTESTED (schema §v5, ruled 2026-09-01).
*
* @param account The wallet address the certificate set derives.
* @param liveTbs `live.pub.fcert` TBS — `activeTransaction` + `activeAccess`.
* @param recoveryTbs `recovery.pub.fcert` TBS — the pre-committed recovery pair.
* @param proof The HOLDER's two signatures over the admission digest —
* the live transaction key (ML-DSA-87) and the live access key
* (SLH-DSA-SHAKE-256s), verified in the precompiles inside this
* transaction. This replaced the CA signature: issuance authority
* is the registrar quorum, possession is this proof, and there is
* no root keypair anywhere.
* @param roles Capability bitmask. The one thing the certificates do not
* say, because capability is this system's decision.
* @param version Monotonic. A rotation that does not advance it is refused.
* @param anchorBlock The block the registrars read the roster at. Ignored
* while bootstrap is open.
* @param approvals The sealed registrar quorum. Empty while bootstrap is
* open. The digest binds the account, both certificates' bytes,
* the roles and the version.
*
* @dev **Both stages, together.** A wallet has four keys in two stages and
* the recovery pair is PRE-COMMITTED — written at `initialize` from the same
* certificate set that determined the address, which is why PQ migration
* takes no key arguments. The two must share a `SerialNumber`: a serial is
* per certificate SET, so two stages disagreeing are two different wallets.
*
* **Chain-attested means pinned, per stage:** the ruled IssuerDN and
* AuthorityKeyId constants, depth exactly 1 (directly under the chain),
* and `maxDelegationDepth == depth` (an end entity signs nothing — the
* same immutable pair `identityTreeLeafOf` discriminates records by).
*/
function registerWallet(
address account,
bytes calldata liveTbs,
bytes calldata recoveryTbs,
AdmissionProof calldata proof,
uint256 roles,
uint64 version,
uint64 anchorBlock,
FinalPqQuorum.Approval[] calldata approvals
) external returns (bytes32 certHash) {
// Read BEFORE the authority check: the quorum path burns this counter
// inside `_requireRegistrarQuorum`, and the proof must bind the value
// the round was built over. The bootstrap path burns it explicitly in
// `_requireAdmissionProof`, so an admission is one-shot in both regimes.
uint64 admissionNonce = _gateNonce[address(this)];
_requireMembershipAuthority(
DOMAIN_REGISTER_WALLET,
keccak256(
abi.encode(account, keccak256(liveTbs), keccak256(recoveryTbs), roles, version)
),
anchorBlock,
approvals
);
FinalCertificate.Parsed memory l = FinalCertificate.parseLive(liveTbs);
FinalCertificate.Parsed memory r = FinalCertificate.parseRecovery(recoveryTbs);
if (l.serial != r.serial) revert StagesDisagree(l.serial, r.serial);
_requireChainAttestedEndEntity(l);
_requireChainAttestedEndEntity(r);
_requireAdmissionProof(account, l, r.certHash, proof, admissionNonce);
certHash = l.certHash;
_write(account, l, r, roles, version, false);
}
/**
* @notice Register or rotate an ISSUER — a third party (or our own
* intermediate) that signs certificates OFF-chain with the keys
* registered here (D2: the superCA).
*
* @param account The issuer's account on this chain.
* @param tbs The single issuer certificate's TBS: two CERT_SIGNING keys
* (ML-DSA-87 + SLH-DSA-SHAKE-256s), no recovery stage — renewing an
* issuer is re-issuing, a governance act rather than a key rotation.
* @param parent The registered parent issuer for a nested intermediate;
* `address(0)` for an issuer hanging directly under the chain.
* @param proof The issuer's OWN two cert-signing keys over the admission
* digest (`recoveryCertHash` slot is zero — there is no recovery
* stage to bind).
*
* @dev Admission is chain-native like any identity: registrar quorum plus
* the holder's PoP. What the v4 delegation rules said survives verbatim as
* LINEAGE — a nested issuer's depth, delegation bound and AuthorityKeyId
* must chain to its registered parent — but no parent SIGNS anything; the
* chain's admission is the issuance.
*
* Ruling 3: a registered issuer always expires (`NotAfter` real, window
* bounded ~2 years) — the passive liveness touchpoint; renewal re-issues
* under the same registered keys with a version bump.
*
* The jurisdiction rule (ruled 2026-09-01, amended): only the trust root
* is jurisdiction-silent. An institution MUST carry its real ISO 3166
* `C=` in its subject DN, matching the `jurisdiction` field of its
* `0x0102` Institution extension — CA/Browser-Forum practice, enforced at
* the door because a verifier's legal recourse starts with knowing where
* an issuer answers for itself.
*/
function registerIssuer(
address account,
bytes calldata tbs,
address parent,
AdmissionProof calldata proof,
uint256 roles,
uint64 version,
uint64 anchorBlock,
FinalPqQuorum.Approval[] calldata approvals
) external returns (bytes32 certHash) {
uint64 admissionNonce = _gateNonce[address(this)];
_requireMembershipAuthority(
DOMAIN_REGISTER_ISSUER,
keccak256(abi.encode(account, keccak256(tbs), parent, roles, version)),
anchorBlock,
approvals
);
FinalCertificate.Parsed memory c = FinalCertificate.parseCa(tbs);
// An issuer that cannot sign is an end entity wearing a profile —
// and an end entity belongs in `registerWallet`.
if (c.depth == 0 || c.maxDelegationDepth <= c.depth) {
revert IssuerCannotSign(c.depth, c.maxDelegationDepth);
}
if (c.notAfter == 0) revert IssuerMustExpire();
if (c.notAfter - c.notBefore > MAX_ISSUER_VALIDITY_MS) {
revert IssuerValidityTooLong(c.notBefore, c.notAfter);
}
if (c.issuerDnHash != CHAIN_ISSUER_DN_HASH) revert WrongIssuerDn(c.issuerDnHash);
_requireLineage(parent, c);
_requireJurisdiction(c);
_requireAdmissionProof(account, c, bytes32(0), proof, admissionNonce);
certHash = c.certHash;
_write(account, c, c, roles | ROLE_CERTIFICATE_AUTHORITY, version, true);
}
/// @notice Ruling 3's validity ceiling for registered issuers, in this
/// chain's milliseconds: two 366-day years.
uint64 public constant MAX_ISSUER_VALIDITY_MS = 2 * 366 days * 1000;
/// @dev The chain-attested end-entity pins, run once per stage.
function _requireChainAttestedEndEntity(FinalCertificate.Parsed memory c) private pure {
if (c.authorityKeyId != CHAIN_AUTHORITY_KEY_ID) revert NotChainAttested(c.authorityKeyId);
if (c.issuerDnHash != CHAIN_ISSUER_DN_HASH) revert WrongIssuerDn(c.issuerDnHash);
if (c.depth != 1 || c.maxDelegationDepth != c.depth) {
revert NotAnEndEntity(c.depth, c.maxDelegationDepth);
}
}
/// @dev The v4 delegation rules, surviving as lineage: a nested issuer
/// chains to a registered, signing-capable parent one level up; a direct
/// issuer hangs under the chain at depth 1.
function _requireLineage(address parent, FinalCertificate.Parsed memory c) private view {
if (parent == address(0)) {
if (c.authorityKeyId != CHAIN_AUTHORITY_KEY_ID) {
revert NotChainAttested(c.authorityKeyId);
}
if (c.depth != 1) revert WrongDepth(c.depth, 1);
return;
}
Identity storage ca = _identity[parent];
if (!hasRole(parent, ROLE_CERTIFICATE_AUTHORITY)) {
revert IssuerNotACertificateAuthority(parent);
}
// Delegation is governed by depth, not by a boolean. `Depth <
// MaxDelegationDepth` permits signing, and a child sits exactly one
// level down — an issuer cannot skip levels to escape its own bound.
if (ca.depth >= ca.maxDelegationDepth) {
revert IssuerMayNotSign(parent, ca.depth, ca.maxDelegationDepth);
}
if (c.depth != ca.depth + 1) revert WrongDepth(c.depth, ca.depth + 1);
if (c.maxDelegationDepth > ca.maxDelegationDepth) {
revert DelegationWidened(c.maxDelegationDepth, ca.maxDelegationDepth);
}
if (c.authorityKeyId != ca.subjectKeyId) {
revert AuthorityKeyIdMismatch(c.authorityKeyId, ca.subjectKeyId);
}
}
/// @dev The jurisdiction rule: a real ISO 3166 alpha-2 `C=` in the subject
/// DN, equal to the Institution extension's `jurisdiction` field. The DN
/// is canonical comma-separated form, so `C=` matches at the start or
/// right after a comma; the component value is exactly two bytes.
function _requireJurisdiction(FinalCertificate.Parsed memory c) private pure {
bytes memory dn = c.subjectDn;
bytes2 country;
bool found = false;
for (uint256 i = 0; i + 4 <= dn.length; i++) {
if ((i == 0 || dn[i - 1] == ",") && dn[i] == "C" && dn[i + 1] == "=") {
// Exactly two bytes, then end-of-DN or the next component.
if (i + 4 < dn.length && dn[i + 4] != ",") revert JurisdictionMissing();
country = bytes2(bytes.concat(dn[i + 2], dn[i + 3]));
found = true;
break;
}
}
if (!found) revert JurisdictionMissing();
// Institution extension: legalNameLength ‖ legalName ‖
// registrationNoLength ‖ registrationNo ‖ jurisdictionLength ‖
// jurisdiction. The jurisdiction must EQUAL the DN's country.
bytes memory ext = c.institutionExt;
if (ext.length < 6) revert JurisdictionMissing();
uint256 q = 2 + (uint256(uint8(ext[0])) << 8 | uint256(uint8(ext[1])));
if (ext.length < q + 2) revert JurisdictionMissing();
q += 2 + (uint256(uint8(ext[q])) << 8 | uint256(uint8(ext[q + 1])));
if (ext.length < q + 2) revert JurisdictionMissing();
uint256 jLen = uint256(uint8(ext[q])) << 8 | uint256(uint8(ext[q + 1]));
q += 2;
if (jLen != 2 || ext.length < q + 2) revert JurisdictionMismatch();
if (bytes2(bytes.concat(ext[q], ext[q + 1])) != country) revert JurisdictionMismatch();
}
/// @dev Verify the holder's PoP: both live-stage families over the
/// admission digest, in the precompiles, inside this transaction. Burns
/// the gate nonce on the bootstrap path (the quorum path burned it in
/// `_requireRegistrarQuorum` already), so an admission is one-shot in
/// both regimes.
function _requireAdmissionProof(
address account,
FinalCertificate.Parsed memory live,
bytes32 recoveryCertHash,
AdmissionProof calldata proof,
uint64 admissionNonce
) private {
bytes memory message = abi.encodePacked(
keccak256(
abi.encode(
DOMAIN_IDENTITY_ADMISSION,
block.chainid,
address(this),
live.certHash,
recoveryCertHash,
admissionNonce
)
)
);
if (
!FinalChainPrecompiles.verifyMlDsa87(live.transactionKey, message, proof.mlDsaSignature)
|| !FinalChainPrecompiles.verifySlhDsa(live.accessKey, message, proof.slhDsaSignature)
) revert AdmissionProofInvalid(account);
if (_gateNonce[address(this)] == admissionNonce) {
_gateNonce[address(this)] = admissionNonce + 1;
}
}
function _write(
address account,
FinalCertificate.Parsed memory live,
FinalCertificate.Parsed memory recovery,
uint256 roles,
uint64 version,
bool isCa
) private {
if (account == address(0)) revert UnknownAccount(account);
if (certificateRevoked[live.certHash]) revert CertificateIsRevoked(live.certHash);
address boundTo = accountOfCertificate[live.certHash];
if (boundTo != address(0) && boundTo != account) {
revert CertificateAlreadyBound(live.certHash, boundTo);
}
Identity storage id = _identity[account];
if (!id.registered) {
_accounts.push(account);
id.registered = true;
} else {
if (version <= id.version) revert VersionNotNewer(id.version, version);
if (id.revoked) revert CertificateIsRevoked(id.certHash);
// A rotation releases the previous certificate's binding. It is NOT
// revoked — a superseded certificate and a compromised one are
// different facts and revocation is the louder of the two.
if (id.certHash != live.certHash) delete accountOfCertificate[id.certHash];
}
id.certHash = live.certHash;
id.recoveryCertHash = recovery.certHash;
id.serial = live.serial;
id.subjectKeyId = live.subjectKeyId;
id.roles = roles;
id.depth = live.depth;
id.maxDelegationDepth = live.maxDelegationDepth;
id.notBefore = live.notBefore;
id.notAfter = live.notAfter;
id.version = version;
// The sender binding moves with the transaction key. The old sender is
// released rather than kept: a rotation is the account disowning that
// key, and a gate that still resolved it would honour a retired key.
address sender = senderFor(live.transactionKey);
address senderBoundTo = accountOfSender[sender];
if (senderBoundTo != address(0) && senderBoundTo != account) {
revert SenderAlreadyBound(sender, senderBoundTo);
}
if (_activeTransactionKey[account].length != 0) {
address previousSender = senderFor(_activeTransactionKey[account]);
if (previousSender != sender) delete accountOfSender[previousSender];
}
accountOfSender[sender] = account;
_activeTransactionKey[account] = live.transactionKey;
_activeAccessKey[account] = live.accessKey;
// A CA has no recovery pair; the two active slots are all it has.
_recoveryTransactionKey[account] = isCa ? bytes("") : recovery.transactionKey;
_recoveryAccessKey[account] = isCa ? bytes("") : recovery.accessKey;
// Cleared on a rotation to a certificate without one, for the same
// reason the encapsulation pair is: a stale seal surviving a rotation
// would let a retired key keep co-signing execution.
_activeSealKey[account] = isCa ? bytes("") : live.sealKey;
// The encapsulation pair, validated before it is stored.
//
// **The registry is where a sender looks up "encapsulate to this
// party", so a malformed key here is not a bad record — it is an
// account nobody can seal an intent to.** The discovery would happen at
// the first attempt, and on the hybrid path it would happen as a pair
// silently reduced to one family, which is identical on the wire. The
// precompiles make it a refusal at registration instead.
//
// Neither is a re-implementation of the KEM: `0x0203` runs FIPS 203
// §7.2's own encapsulation-key check and `0x0207` runs the structural
// check HQC-5's encoding admits. Encapsulation is a sender operation
// and decapsulation needs the secret key, so nothing more belongs here.
//
// A CA is sealed to by nobody and carries no encapsulation stage, so
// its slots are cleared rather than checked.
_storeKemPair(account, isCa, live.kemMlKem, live.kemHqc, true);
_storeKemPair(account, isCa, recovery.kemMlKem, recovery.kemHqc, false);
accountOfCertificate[live.certHash] = account;
emit IdentityRegistered(account, live.certHash, roles, version);
// Same-tx: a registration or rotation is visible to every execution
// chain's admission set the moment it is visible here.
_projectIdentity(account);
}
/**
* @dev Store one stage's encapsulation pair, or clear it.
*
* Empty is legitimate and is not the same as absent-and-wrong: a CA has no
* encapsulation stage, and a certificate issued before v4 carries none.
* `FinalCertificate.parse` has already refused the half-populated case, so
* by here the pair is both or neither.
*
* Cleared rather than left alone on a rotation to an empty pair. A stale
* key surviving a rotation is a sender encapsulating to a credential the
* account has disowned, and the intent then never decrypts — the failure
* mode with no error attached, and the one this whole pairing exists to
* avoid.
*/
function _storeKemPair(address account, bool isCa, bytes memory mlKem, bytes memory hqc, bool isLive)
private
{
if (isCa || mlKem.length == 0) {
delete (isLive ? _activeKemMlKem : _recoveryKemMlKem)[account];
delete (isLive ? _activeKemHqc : _recoveryKemHqc)[account];
return;
}
if (!FinalChainPrecompiles.isWellFormedMlKem1024(mlKem)) {
revert MalformedEncapsulationKey(account, FinalCertificate.ALG_ML_KEM_1024);
}
if (!FinalChainPrecompiles.isWellFormedHqc5(hqc)) {
revert MalformedEncapsulationKey(account, FinalCertificate.ALG_HQC_5);
}
if (isLive) {
_activeKemMlKem[account] = mlKem;
_activeKemHqc[account] = hqc;
} else {
_recoveryKemMlKem[account] = mlKem;
_recoveryKemHqc[account] = hqc;
}
}
/// @notice Grant or withdraw capabilities without rotating keys.
/// @dev Separate from registration because the two have different
/// cadences: a role changes when a service's job changes, a key changes
/// when it is compromised or aged out. Folding them together would force a
/// key rotation to express a role change.
function setRoles(
address account,
uint256 roles,
uint64 anchorBlock,
FinalPqQuorum.Approval[] calldata approvals
) external {
_requireMembershipAuthority(
DOMAIN_SET_ROLES, keccak256(abi.encode(account, roles)), anchorBlock, approvals
);
Identity storage id = _identity[account];
if (!id.registered) revert UnknownAccount(account);
if (id.revoked) revert CertificateIsRevoked(id.certHash);
uint256 previous = id.roles;
id.roles = roles;
_requireRegistrarQuorumReachable();
emit IdentityRolesChanged(account, previous, roles);
// Roles are not in the tree-8 leaf, so this rewrites the same value —
// kept anyway so "every identity mutation projects" has no exceptions
// to remember.
_projectIdentity(account);
}
/// @dev Once sealed, no mutation may leave the registrar quorum unreachable
/// — that is the one change nothing could ever undo. Checked after the
/// write so the count reflects it.
function _requireRegistrarQuorumReachable() private view {
if (!bootstrapSealed) return;
uint256 sealable = sealableMemberCount(ROLE_REGISTRAR);
if (sealable < registrarThreshold) {
revert RegistrarThresholdUnreachable(sealable, registrarThreshold);
}
}
/// @notice Revoke an identity and its certificate. Irreversible.
/// @param chainIds The chains whose LMS-key slots this account holds — the
/// registrars supply the list (the digest binds it) because a mapping
/// cannot enumerate its own keys. Each named slot's current fingerprint is
/// recorded into the revocation log same-tx; a chain with no slot is
/// skipped, and a fingerprint missed by an incomplete list stays
/// permanently recordable through the log's permissionless door, since a
/// revoked account never regains standing.
/// @dev Clears the roles as well as setting the flag. Both are checked
/// everywhere, but leaving a revoked record carrying roles invites a future
/// reader that checks only one of them.
function revoke(
address account,
uint64[] calldata chainIds,
uint64 anchorBlock,
FinalPqQuorum.Approval[] calldata approvals
) external {
_requireMembershipAuthority(
DOMAIN_REVOKE, keccak256(abi.encode(account, chainIds)), anchorBlock, approvals
);
Identity storage id = _identity[account];
if (!id.registered) revert UnknownAccount(account);
id.revoked = true;
id.roles = 0;
certificateRevoked[id.certHash] = true;
_requireRegistrarQuorumReachable();
emit IdentityRevoked(account, id.certHash);
// AFTER the flag lands, so the log's own gate sees the permanent
// transition it requires.
for (uint256 i = 0; i < chainIds.length; i++) {
LmsKey storage k = _lmsKey[account][chainIds[i]];
if (k.registered) _recordRevokedSigner(lmsSignerId(k.keyId, k.height, k.root));
}
_projectIdentity(account);
}
/**
* @notice Root-plane GLOBAL certificate revocation, by `certHash` (D5).
*
* @dev The half of the one revocation lane that gates registration and
* covers break-glass: any certificate — registered, off-chain-issued, or
* never seen — can be killed by handle under the registrar quorum. When
* the handle is a registered identity's CURRENT certificate the identity
* falls with it (flag, roles, same-tx projection), so a break-glass by
* handle is never weaker than {revoke} — it only skips the LMS-slot
* enumeration, which stays permanently recordable through the revocation
* log's permissionless door.
*/
function revokeCertificate(
bytes32 certHash,
uint64 anchorBlock,
FinalPqQuorum.Approval[] calldata approvals
) external {
_requireMembershipAuthority(
DOMAIN_REVOKE_CERTIFICATE, keccak256(abi.encode(certHash)), anchorBlock, approvals
);
certificateRevoked[certHash] = true;
address bound = accountOfCertificate[certHash];
if (bound != address(0)) {
Identity storage id = _identity[bound];
if (!id.revoked) {
id.revoked = true;
id.roles = 0;
_requireRegistrarQuorumReachable();
emit IdentityRevoked(bound, certHash);
_projectIdentity(bound);
}
}
emit CertificateRevoked(certHash, address(0));
}
/**
* @notice The ISSUING identity's half of the revocation lane: a registered
* issuer revokes a certificate it signed OFF-chain, by `certHash`.
*
* @dev "Sub-issuer and us alike" (D5) — but SCOPED: this records WHO
* revoked, and a verifier honours the entry only when the revoker is the
* certificate's own issuer (which the verifier knows — it holds the
* cert). It deliberately does NOT set the global `certificateRevoked`
* flag: that flag gates registration, and letting any registered issuer
* set it for an arbitrary handle would be a griefing lane over other
* people's certificates.
*
* Anyone may SUBMIT; authority is the two signatures — the issuer's
* registered cert-signing keys over a digest binding this registry, the
* chain, the handle and the issuer's own gate nonce. One-way: the first
* revoker of a handle is recorded and a second write is refused, because
* "revoked twice by two parties" is two facts where the lane models one.
*/
function revokeIssuedCertificate(
address issuer,
bytes32 certHash,
AdmissionProof calldata proof
) external {
if (!hasRole(issuer, ROLE_CERTIFICATE_AUTHORITY)) {
revert IssuerNotACertificateAuthority(issuer);
}
if (certificateRevokedBy[certHash] != address(0)) revert CertificateIsRevoked(certHash);
uint64 nonce = _gateNonce[issuer];
_gateNonce[issuer] = nonce + 1;
bytes memory message = abi.encodePacked(
keccak256(
abi.encode(
DOMAIN_ISSUER_CERT_REVOCATION,
block.chainid,
address(this),
issuer,
certHash,
nonce
)
)
);
if (
!FinalChainPrecompiles.verifyMlDsa87(
_activeTransactionKey[issuer], message, proof.mlDsaSignature
)
|| !FinalChainPrecompiles.verifySlhDsa(
_activeAccessKey[issuer], message, proof.slhDsaSignature
)
) revert AdmissionProofInvalid(issuer);
certificateRevokedBy[certHash] = issuer;
emit CertificateRevoked(certHash, issuer);
}
// ---------------------------------------------------------------- views
/// @notice The full identity record. `registered` is the field to branch on.
function identityOf(address account) external view returns (Identity memory) {
return _identity[account];
}
/// @notice `activeTransaction` — ML-DSA-87. What a quorum verifies against.
function activeTransactionKeyOf(address account) external view returns (bytes memory) {
return _activeTransactionKey[account];
}
/// @notice `activeAccess` — SLH-DSA-SHAKE-256s. Identity, and guardianship.
function activeAccessKeyOf(address account) external view returns (bytes memory) {
return _activeAccessKey[account];
}
/// @notice `activeSeal` — SLH-DSA-SHAKE-256s. What `FinalPqQuorum` verifies
/// an execution-class approval's `seal` against. Empty when the identity
/// carries no seal, in which case it cannot take part in a sealed quorum.
function activeSealKeyOf(address account) external view returns (bytes memory) {
return _activeSealKey[account];
}
/// @notice `recoveryTransaction`. Authorizes rotating this account's own
/// credentials and nothing else. Empty for a CA.
function recoveryTransactionKeyOf(address account) external view returns (bytes memory) {
return _recoveryTransactionKey[account];
}
/// @notice `recoveryAccess`. Empty for a CA.
function recoveryAccessKeyOf(address account) external view returns (bytes memory) {
return _recoveryAccessKey[account];
}
/// @notice The four commitments, in the order tree 1's leaf wants them.
/// @dev keccak, not SHA3 — these feed `FinalWalletFactory.accountStateLeafHash`,
/// which every other chain verifies with, and that one hashes with keccak.
function keyCommitments(address account)
external
view
returns (
bytes32 liveAccess,
bytes32 liveTransaction,
bytes32 recoveryAccess,
bytes32 recoveryTransaction
)
{
liveAccess = keccak256(_activeAccessKey[account]);
liveTransaction = keccak256(_activeTransactionKey[account]);
recoveryAccess = keccak256(_recoveryAccessKey[account]);
recoveryTransaction = keccak256(_recoveryTransactionKey[account]);
}
/**
* @notice The tree-8 leaf `account` currently earns: the execution
* chains' identity leaf while the identity stands, zero once it
* does not.
*
* @dev The leaf VALUE is `keccak256(DOMAIN_IDENTITY_LEAF ‖ serial ‖
* keysHash)` — byte-identical to `IdentityRootModule.identityLeafHash`,
* which is also the `certHash` inside the wallet's CREATE2 derivation —
* with `keysHash` folded exactly as the certificate issuer folds it:
* `keccak256(activeAccess ‖ activeTransaction ‖ recoveryAccess ‖
* recoveryTransaction ‖ activeKem ‖ recoveryKem)`, six commitment words
* packed in slot order (`minePqVanityCerts.cjs` is the reference encoder;
* the parity test pins this function against the premined fixtures).
*
* Zero — the empty slot's own value, unprovable as a leaf because no
* certificate hashes to it — for anything that must not admit a wallet
* creation: a revoked identity, one outside its validity window, and any
* CA. The CA exclusion is structural, not a role read: an end entity has
* `depth == maxDelegationDepth` (it issues nothing), a CA never does, and
* the depth pair is immutable per version where roles are not.
*
* Lives HERE rather than on `FinalStateTrees` (whose tree 8 consumes it)
* because every input is this contract's storage and the trees contract
* sits against EIP-170.
*/
function identityTreeLeafOf(address account) external view returns (bytes32) {
Identity storage id = _identity[account];
if (!id.registered) revert UnknownAccount(account);
if (id.revoked || !_withinValidity(id)) return bytes32(0);
if (id.depth != id.maxDelegationDepth) {
// D7 (ruled 2026-09-01): an ISSUER exists in tree 8 under its own
// domain, so its record is stapleable for offline licence
// verification. `certHash` suffices (it covers the whole TBS and
// the verifier holds the cert), `version` makes supersession move
// the leaf, and the third word RESERVES the issuer's own
// certificate-tree anchor — zero until wired. The distinct domain
// does the wallet-admission exclusion the zero projection used to
// do; zero-on-revoke above is now load-bearing for both record
// kinds (a fresh staple is an unrevoked statement).
return keccak256(
abi.encodePacked(DOMAIN_ISSUER_LEAF, id.certHash, uint64(id.version), bytes32(0))
);
}
bytes32 liveKem = keccak256(
abi.encodePacked(DOMAIN_KEM_BUNDLE, _activeKemMlKem[account], _activeKemHqc[account]));
bytes32 recoveryKem = keccak256(
abi.encodePacked(DOMAIN_KEM_BUNDLE, _recoveryKemMlKem[account], _recoveryKemHqc[account]));
bytes32 keysHash = keccak256(
abi.encodePacked(
keccak256(_activeAccessKey[account]),
keccak256(_activeTransactionKey[account]),
keccak256(_recoveryAccessKey[account]),
keccak256(_recoveryTransactionKey[account]),
liveKem,
recoveryKem
)
);
return keccak256(abi.encodePacked(DOMAIN_IDENTITY_LEAF, id.serial, keysHash));
}
/// @notice Per-stage encapsulation commitments, in `AccountStateLeaf` order.
/// @dev One word per STAGE, over both of that stage's KEM public keys. The
/// pair is the unit — an account holds both or neither — so committing them
/// separately would model a state the protocol does not recognise, and every
/// downstream record would carry two words where one says the same thing.
///
/// An account registered before the encapsulation slots existed hashes the
/// empty string here rather than reverting: `syncIdentities` must keep
/// projecting it, and a leaf that cannot be built is a party that cannot be
/// revoked.
function kemCommitments(address account)
external
view
returns (bytes32 liveKem, bytes32 recoveryKem)
{
liveKem = keccak256(
abi.encodePacked(DOMAIN_KEM_BUNDLE, _activeKemMlKem[account], _activeKemHqc[account]));
recoveryKem = keccak256(
abi.encodePacked(DOMAIN_KEM_BUNDLE, _recoveryKemMlKem[account], _recoveryKemHqc[account]));
}
/// @notice The encapsulation keys themselves, for a party composing a message.
function kemKeysOf(address account)
external
view
returns (bytes memory activeMlKem, bytes memory activeHqc)
{
return (_activeKemMlKem[account], _activeKemHqc[account]);
}
// ------------------------------------------------------------- senders
/**
* @notice The Final Chain sender a transaction key produces.
* @dev `keccak256(uint8(4) ‖ publicKey)[12:]` — byte-identical to what the
* node derives from a type-0x46 envelope and to the backend's
* `pqTransaction.senderOf`. Pure, so a client can compute it from a
* certificate before the identity is registered.
*/
function senderFor(bytes memory transactionKey) public pure returns (address) {
return address(uint160(uint256(keccak256(abi.encodePacked(ENVELOPE_ALG_ML_DSA_87, transactionKey)))));
}
/// @notice The sender `account`'s transactions arrive from, or zero for an
/// account with no transaction key on record.
function senderOf(address account) external view returns (address) {
bytes storage key = _activeTransactionKey[account];
if (key.length == 0) return address(0);
return senderFor(key);
}
/// @notice `hasRole` for a `msg.sender`: resolves the sender to its identity
/// first. False for a sender no identity claims.
function senderHasRole(address sender, uint256 roleMask) external view returns (bool) {
address account = accountOfSender[sender];
return account != address(0) && hasRole(account, roleMask);
}
/// @notice How many accounts carrying `roleMask` also hold a seal key —
/// the members that can take part in a sealed quorum.
function sealableMemberCount(uint256 roleMask) public view returns (uint256 sealable) {
uint256 n = _accounts.length;
for (uint256 i = 0; i < n; i++) {
address a = _accounts[i];
if (hasRole(a, roleMask) && _activeSealKey[a].length != 0) sealable++;
}
}
/// @notice Number of registered accounts.
function accountCount() external view returns (uint256) {
return _accounts.length;
}
/// @notice Registered account by index, in registration order.
function accountAt(uint256 index) external view returns (address) {
return _accounts[index];
}
/// @notice Every account carrying every bit in `roleMask`.
/// @dev A view, so the O(n) scan costs nothing. Callers that need this in a
/// transaction should pass the member list explicitly instead — see
/// `FinalPqQuorum`, which takes signers rather than searching for them.
function accountsWithRole(uint256 roleMask) external view returns (address[] memory found) {
uint256 n = _accounts.length;
address[] memory buf = new address[](n);
uint256 count;
for (uint256 i = 0; i < n; i++) {
if (hasRole(_accounts[i], roleMask)) {
buf[count++] = _accounts[i];
}
}
found = new address[](count);
for (uint256 i = 0; i < count; i++) {
found[i] = buf[i];
}
}
/**
* @notice How many accounts could satisfy a quorum for `roleMask` right now.
* @dev The number a threshold has to be reachable against. A threshold above
* it is not a strict quorum, it is a quorum that cannot be met — and the way
* that presents is an operation that reverts forever with nothing naming the
* roster as the cause.
*/
function liveMemberCount(uint256 roleMask) public view returns (uint256 live) {
uint256 n = _accounts.length;
for (uint256 i = 0; i < n; i++) {
if (hasRole(_accounts[i], roleMask)) live++;
}
}
/**
* @notice Whether `account` currently carries every bit in `roleMask`.
* @dev Every gate in this system asks this one question, so every gate gets
* the same answer: registered, not revoked, inside its validity window, and
* holding the capability. A caller that checked only the role bit would
* accept an expired certificate.
*
* `roleMask == 0` is false. A zero mask asks nothing and must not read as
* "yes" — that is the shape of an uninitialised configuration variable, and
* the one reading it should not be a universal pass.
*/
function hasRole(address account, uint256 roleMask) public view returns (bool) {
if (roleMask == 0) return false;
Identity storage id = _identity[account];
if (!id.registered || id.revoked) return false;
if (id.roles & roleMask != roleMask) return false;
return _withinValidity(id);
}
/// @notice Whether `account` is registered, unrevoked and in date,
/// regardless of capability.
function isActive(address account) public view returns (bool) {
Identity storage id = _identity[account];
return id.registered && !id.revoked && _withinValidity(id);
}
function _withinValidity(Identity storage id) private view returns (bool) {
if (id.notBefore != 0 && FinalChainTime.nowMs() < id.notBefore) return false;
if (id.notAfter != 0 && FinalChainTime.nowMs() >= id.notAfter) return false;
return true;
}
}
contracts/finalchain/FinalPhiSupply.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;
import {FinalIdentityRegistry} from "./FinalIdentityRegistry.sol";
import {FinalPqQuorum} from "./FinalPqQuorum.sol";
/**
* @title FinalPhiSupply
* @notice The 100,000,000 PHI, and the only place that can see all of them.
*
* @dev ## What this exists to fix
*
* `PHIToken` on every execution chain deploys with no supply and can only gain
* it through `spawn`, so a chain can never hold more than Final Chain issued it.
* That property is local and structural. The GLOBAL one was not:
*
* > The global cap still cannot be enforced on-chain — no chain sees the others
* > — so it rests on this ledger's integrity.
*
* Final Chain does see the others, because it is what issues to them. This
* contract is that view made into an invariant: every chain's outstanding
* allocation is a number here, and no path exists that changes one without
* changing `held` by the same amount in the opposite direction.
*
* held + Σ over chains of allocatedTo[chainRef] == TOTAL_SUPPLY
*
* Checked after every mutation and reverted on violation, so "100M is fixed"
* stops being a property the backend must not break and becomes one it cannot.
*
* ## What this is NOT
*
* **Not a token, and deliberately.** There are no per-wallet balances here. A
* wallet's PHI is the **tree 2** record — `available`, the lock and its
* exposures per `(wallet, chainId)`, published by the PHI publishers from the
* execution chains and the admitted intents. Holding balances here as well
* would make two records of one asset that mutate independently. This contract
* knows totals per chain and nothing about who holds them — and its invariant
* IS the conservation of PHI: nothing off-chain re-derives it, and a chain's
* supply lagging its allocation during a transfer is the order of operations,
* not drift.
*
* **Not the gas token.** This chain charges gas in vETH. PHI being native is
* for Final Chain proper; here it would put a wallet's PHI in two places — its
* native balance and its tree-2 leaf — and the base fee would burn supply on
* every transaction, since EIP-1559 destroys it rather than paying it out.
*
* ## Cadence: this is not on the hot path
*
* `spawn` and `despawn` run on the **scheduled per-chain reconciliation**, sized
* to bring that chain's paymaster float back to its 2% target — not per
* operation, and not per liquidation.
*
* **The 2% is of THAT CHAIN's PHI in use, not of the 100M in circulation.**
* The two read almost identically and compute very differently: on a chain
* holding 1M PHI the target is 20,000, not the 2,000,000 that 2% of the global
* supply would give — a hundred times the float, drawn off every other chain to
* sit idle. Per chain, the float scales with that chain's own allocation and
* needs no re-tuning as allocation shifts between chains, which is the reason
* it is a fraction rather than a fixed amount. `allocatedTo[chainRef]` is the
* base; `totalAllocated` is never the base.
*
* That is what makes liquidations and manual reconciliations instant on the
* chain they happen on: between sweeps the paymaster serves them out of float,
* and Final Chain is not in the loop at all. Wiring either entrypoint per
* operation would put a quorum round trip in front of a liquidation, which is
* the one path that cannot afford one — and it would do so for no gain, because
* the float exists precisely so the allocation is already there.
*
* Refill is to TARGET, not to zero. A flat float makes the next user pay the
* same latency, and on a busy chain that turns every operation into a refill.
*
* ## Ordering
*
* Final Chain decides and the chains follow. A spawn debits `held` HERE first
* and the remote mint proves against the record this emits, so the destination
* can never mint ahead of the source debit — which is the one rule
* "executing-first" does not imply on its own, and the reason
* `projection.js` exists. Issuing out of Final Chain is safe by construction
* because the debit is already durable; legacy-to-legacy is the dangerous
* direction and it routes through here rather than between chains.
*/
contract FinalPhiSupply {
// ------------------------------------------------------------------ types
/// @notice One chain's outstanding allocation.
struct Allocation {
/// @dev Spawned to this chain and not yet returned. Never exceeds
/// TOTAL_SUPPLY, because `held` cannot go below zero.
uint256 outstanding;
/// @dev Monotonic per chain. What a consumer compares to tell a stale
/// record from a current one without needing a round.
uint64 epoch;
}
// -------------------------------------------------------------- constants
/// @notice 100,000,000 PHI, 18 decimals. Fixed for the life of the protocol.
///
/// @dev A constant rather than a constructor argument for the same reason
/// `PHIToken` takes no supply argument: a value someone supplies is a
/// value someone can supply twice.
uint256 public constant TOTAL_SUPPLY = 100_000_000 ether;
bytes32 internal constant ACTION_SPAWN = keccak256("FinalPhiSupply.spawn.v01");
bytes32 internal constant ACTION_DESPAWN = keccak256("FinalPhiSupply.despawn.v01");
bytes32 internal constant ACTION_MOVE = keccak256("FinalPhiSupply.move.v01");
// ------------------------------------------------------------------ state
FinalIdentityRegistry public immutable registry;
/// @dev Can `configure` and `seal`, and nothing else. Zero once sealed.
/// @dev Registrar-quorum action, verified by the registry with this
/// contract as the verifying contract.
bytes32 public constant ACTION_CONFIGURE = keccak256("FINAL_PHI_SUPPLY_CONFIGURE_v01");
/// @dev Registrar-quorum action: a fresh supply taking over the previous
/// supply's ledger (the NO-WIPE redeploy).
bytes32 public constant ACTION_SEED = keccak256("FINAL_PHI_SUPPLY_SEED_v01");
address public admin;
/// @dev `ROLE_PHI_PUBLISHER`. The role bit itself is the registry's, so
/// membership changes there and not here.
uint256 public publisherRole;
/// @dev How many of the quorum must approve. Follows the fleet rule of
/// floor(2N/3) — three of five — rather than being tuned per contract.
///
/// Settable rather than immutable for one reason: the roster grows. A
/// threshold fixed at deploy against three members stays 2-of-N when
/// the fleet reaches five, and a quorum that does not track its roster
/// weakens silently as the roster it guards gets larger.
uint256 public threshold;
/// @notice PHI on Final Chain, allocated to no execution chain.
uint256 public held;
/// @notice Per-chain outstanding allocation, by CAIP-style chain reference.
mapping(bytes32 => Allocation) public allocatedTo;
/// @notice The sum of every `allocatedTo[*].outstanding`.
///
/// @dev Maintained incrementally rather than summed on read: the mapping
/// cannot be iterated, and an invariant that can only be checked by an
/// off-chain sweep is not an invariant.
uint256 public totalAllocated;
/// @dev Replay protection for the quorum digest.
uint64 public nonce;
/// @dev Consumed-once per `(chainRef, originSeqId)`. One despawn on a chain
/// can never become two credits here — the mirror of the same rule
/// `PHIToken.spawn` enforces in the other direction.
mapping(bytes32 => mapping(uint256 => bool)) public consumedDespawn;
// ----------------------------------------------------------------- errors
error NotAdmin(address caller);
error ThresholdUnreachable(uint256 live, uint256 wanted);
error NotConfigured();
error ZeroAmount();
error InsufficientHeld(uint256 want, uint256 have);
error InsufficientAllocation(bytes32 chainRef, uint256 want, uint256 have);
error AlreadyConsumed(bytes32 chainRef, uint256 originSeqId);
error SupplyInvariantBroken(uint256 held, uint256 allocated);
/// @notice A move names the same chain twice, or no chain.
error InvalidMove(bytes32 source, bytes32 target);
/// @notice The ledger can be seeded only into a fresh supply.
error NotFresh();
/// @notice `seed`'s parallel arrays disagree in length, or a ref is zero
/// or carries epoch 0 (a ref the old supply never touched).
error SeedShapeMismatch();
/// @notice `seed` names one chain ref twice.
error SeedRefRepeated(bytes32 chainRef);
// ----------------------------------------------------------------- events
event Spawned(bytes32 indexed chainRef, uint256 amount, uint256 outstanding, uint64 epoch, uint64 seq);
event Despawned(bytes32 indexed chainRef, uint256 amount, uint256 outstanding, uint64 epoch, uint256 originSeqId);
/// @notice Allocation moved between two execution chains in one record.
/// `seq` names the move for the target's spawn and the source's closing
/// despawn; `held` is untouched.
event Moved(
bytes32 indexed source,
bytes32 indexed target,
uint256 amount,
uint256 sourceOutstanding,
uint256 targetOutstanding,
uint64 seq
);
event SupplyConfigured(uint256 role, uint256 threshold);
event Sealed();
/// @notice A fresh supply took over the previous supply's ledger.
event Seeded(uint256 allocations, uint256 despawns, uint64 nonce);
// ------------------------------------------------------------ constructor
constructor(FinalIdentityRegistry registry_, address admin_) {
registry = registry_;
admin = admin_;
// The whole supply starts here, unallocated. This is the "created once"
// in "created once, on Final Chain" — and it happens exactly once,
// because a constant cannot be passed twice.
held = TOTAL_SUPPLY;
}
// ------------------------------------------------------------- bootstrap
/**
* @notice Point at the publisher role and set how many of it must approve.
*
* @dev Refuses a threshold the roster cannot reach. Without that check the
* failure is not a revert here but a `spawn` that no set of signatures
* can ever satisfy — supply frozen by a typo, and discovered at the
* first reconciliation rather than at configure time.
*/
function configure(
uint256 role,
uint256 k,
uint64 anchorBlock,
FinalPqQuorum.Approval[] calldata approvals
) external {
// The admin alone while this contract's window is open; the sealed
// `ROLE_REGISTRAR` quorum afterwards, exactly as on the registry and
// the trees. Before the quorum path existed, `seal()` froze this
// configuration forever — a publisher set that could never re-threshold.
if (msg.sender != admin) {
registry.requireRegistrarQuorum(
ACTION_CONFIGURE, keccak256(abi.encode(role, k)), anchorBlock, approvals
);
}
if (k != 0) {
uint256 live = registry.liveMemberCount(role);
if (live < k) revert ThresholdUnreachable(live, k);
}
publisherRole = role;
threshold = k;
emit SupplyConfigured(role, k);
}
/// @notice Close the bootstrap window. One way.
function seal() external {
if (msg.sender != admin) revert NotAdmin(msg.sender);
admin = address(0);
emit Sealed();
}
/**
* @notice Take over the previous supply's ledger: every chain's outstanding
* allocation and epoch, every consumed despawn, and the nonce — so
* a redeployed supply says exactly what the old one said, and every
* `seq` it will ever issue stays above every seq a `PHIToken` has
* already consumed. NO-WIPE redeploy (ruled 2026-09-03); the supply
* gained the lane on 2026-09-05, when the registry cascade made it
* a fresh contract.
* @dev Only into a fresh supply (nothing allocated, nonce 0). The
* registry's bootstrap admin inside its window, the sealed
* `ROLE_REGISTRAR` quorum afterwards — the door every other
* state-plane seed uses. `held` is DERIVED (`TOTAL_SUPPLY - Σ
* outstanding`) and the invariant asserted, so a list that does not
* add up reverts rather than seeds.
*/
function seed(
bytes32[] calldata refs,
uint256[] calldata outstanding,
uint64[] calldata epochs,
bytes32[] calldata despawnRefs,
uint256[] calldata despawnSeqs,
uint64 nonce_,
uint64 anchorBlock,
FinalPqQuorum.Approval[] calldata approvals
) external {
if (registry.bootstrapSealed() || msg.sender != registry.bootstrapAdmin()) {
registry.requireRegistrarQuorum(
ACTION_SEED,
keccak256(abi.encode(refs, outstanding, epochs, despawnRefs, despawnSeqs, nonce_)),
anchorBlock,
approvals
);
}
if (nonce != 0 || totalAllocated != 0) revert NotFresh();
if (refs.length != outstanding.length || refs.length != epochs.length) revert SeedShapeMismatch();
if (despawnRefs.length != despawnSeqs.length) revert SeedShapeMismatch();
uint256 allocated;
for (uint256 i = 0; i < refs.length; i++) {
if (refs[i] == bytes32(0) || epochs[i] == 0) revert SeedShapeMismatch();
Allocation storage a = allocatedTo[refs[i]];
if (a.epoch != 0) revert SeedRefRepeated(refs[i]);
a.outstanding = outstanding[i];
a.epoch = epochs[i];
allocated += outstanding[i];
}
if (allocated > TOTAL_SUPPLY) revert InsufficientHeld(allocated, TOTAL_SUPPLY);
totalAllocated = allocated;
held = TOTAL_SUPPLY - allocated;
for (uint256 i = 0; i < despawnRefs.length; i++) {
consumedDespawn[despawnRefs[i]][despawnSeqs[i]] = true;
}
nonce = nonce_;
_assertInvariant();
emit Seeded(refs.length, despawnRefs.length, nonce_);
}
// ------------------------------------------------------------------ views
/// @notice The invariant, as a number a caller can check without trusting us.
function accountedSupply() external view returns (uint256) {
return held + totalAllocated;
}
function outstandingOn(bytes32 chainRef) external view returns (uint256) {
return allocatedTo[chainRef].outstanding;
}
// ------------------------------------------------------------- mutations
/**
* @notice Allocate PHI to an execution chain. The remote mint proves against
* the `Spawned` record this emits.
*
* @dev Debits `held` BEFORE anything can mint remotely, which is what makes
* "never mint on the destination before the burn on the source is
* confirmed" hold for this direction by construction.
*/
function spawn(
bytes32 chainRef,
uint256 amount,
uint64 anchorBlock,
FinalPqQuorum.Approval[] calldata approvals
) external returns (uint64 seq) {
uint256 k = threshold;
if (k == 0) revert NotConfigured();
if (amount == 0) revert ZeroAmount();
if (amount > held) revert InsufficientHeld(amount, held);
uint64 n = nonce;
FinalPqQuorum.require_(
registry,
approvals,
FinalPqQuorum.digest(
address(this), ACTION_SPAWN, anchorBlock, keccak256(abi.encode(n, chainRef, amount))
),
publisherRole,
k,
FinalPqQuorum.ALG_ML_DSA_87,
anchorBlock,
false
);
nonce = n + 1;
Allocation storage a = allocatedTo[chainRef];
unchecked {
// `amount <= held` was checked, and `totalAllocated + amount` cannot
// exceed TOTAL_SUPPLY for the same reason.
held -= amount;
a.outstanding += amount;
totalAllocated += amount;
}
a.epoch += 1;
_assertInvariant();
emit Spawned(chainRef, amount, a.outstanding, a.epoch, n);
return n;
}
/**
* @notice Return PHI from an execution chain, against a burn already
* performed there.
*
* @dev `originSeqId` is the despawn's sequence on the source chain and is
* consumed once. Gaps and out-of-order arrival are both normal — the
* source sequences, this does not re-order.
*/
function despawn(
bytes32 chainRef,
uint256 amount,
uint256 originSeqId,
uint64 anchorBlock,
FinalPqQuorum.Approval[] calldata approvals
) external {
uint256 k = threshold;
if (k == 0) revert NotConfigured();
if (amount == 0) revert ZeroAmount();
if (consumedDespawn[chainRef][originSeqId]) revert AlreadyConsumed(chainRef, originSeqId);
Allocation storage a = allocatedTo[chainRef];
if (amount > a.outstanding) revert InsufficientAllocation(chainRef, amount, a.outstanding);
uint64 n = nonce;
FinalPqQuorum.require_(
registry,
approvals,
FinalPqQuorum.digest(
address(this),
ACTION_DESPAWN,
anchorBlock,
keccak256(abi.encode(n, chainRef, amount, originSeqId))
),
publisherRole,
k,
FinalPqQuorum.ALG_ML_DSA_87,
anchorBlock,
false
);
nonce = n + 1;
consumedDespawn[chainRef][originSeqId] = true;
unchecked {
a.outstanding -= amount;
totalAllocated -= amount;
held += amount;
}
a.epoch += 1;
_assertInvariant();
emit Despawned(chainRef, amount, a.outstanding, a.epoch, originSeqId);
}
/**
* @notice Move allocation from one execution chain to another, in one record.
*
* @dev **Final Chain leads.** A cross-chain PHI transfer is: pre-approved
* intent → transfer lock on the source → finality → THIS → the target
* spawns → the source burns as the CLOSING step. Both allocations
* change here, together, before either chain acts, and `held` is
* untouched — the PHI is not leaving circulation, it is changing where
* it sits. Recorded as one mutation so there is no instant at which the
* per-chain amounts sum to anything but the same total.
*
* `spawn` / `despawn` stay for reconciliation, where `held` does move.
* Routing a transfer through them instead would pass through `held`
* and make a legacy-to-legacy move look, for one transaction, like a
* return to Final Chain that it is not.
*/
function move(
bytes32 source,
bytes32 target,
uint256 amount,
uint64 anchorBlock,
FinalPqQuorum.Approval[] calldata approvals
) external returns (uint64 seq) {
uint256 k = threshold;
if (k == 0) revert NotConfigured();
if (amount == 0) revert ZeroAmount();
if (source == bytes32(0) || target == bytes32(0) || source == target) revert InvalidMove(source, target);
Allocation storage from = allocatedTo[source];
if (amount > from.outstanding) revert InsufficientAllocation(source, amount, from.outstanding);
uint64 n = nonce;
FinalPqQuorum.require_(
registry,
approvals,
FinalPqQuorum.digest(
address(this), ACTION_MOVE, anchorBlock, keccak256(abi.encode(n, source, target, amount))
),
publisherRole,
k,
FinalPqQuorum.ALG_ML_DSA_87,
anchorBlock,
false
);
nonce = n + 1;
Allocation storage to = allocatedTo[target];
unchecked {
// `amount <= from.outstanding` was checked; `totalAllocated` is
// unchanged by construction, so the invariant cannot move.
from.outstanding -= amount;
to.outstanding += amount;
}
from.epoch += 1;
to.epoch += 1;
_assertInvariant();
emit Moved(source, target, amount, from.outstanding, to.outstanding, n);
return n;
}
// ---------------------------------------------------------------- internal
/**
* @dev The reason this contract exists, checked on every path that moves a
* number. Both mutations are written to preserve it by construction, so
* a revert here means a bug in this contract rather than bad input —
* which is exactly when an assertion earns its gas.
*/
function _assertInvariant() internal view {
if (held + totalAllocated != TOTAL_SUPPLY) revert SupplyInvariantBroken(held, totalAllocated);
}
}
contracts/finalchain/FinalPqQuorum.sol
// SPDX-License-Identifier: BUSL-1.1
// Copyright (c) 2024-2026 Final DeFi
// Licensed under the Business Source License 1.1 (the "License")
//
// Change Date: 2029-01-01
// Change License: GPL-2.0-or-later
//
// @author Final DeFi
// @version 1.0.0
pragma solidity ^0.8.20;
import {FinalChainPrecompiles} from "./FinalChainPrecompiles.sol";
import {FinalIdentityRegistry} from "./FinalIdentityRegistry.sol";
/**
* @title FinalPqQuorum
* @notice K-of-N approval where the signatures are post-quantum and the chain
* is what checks them.
*
* @dev This library is the reason Final Chain exists in this design.
*
* `FinalBackend/src/pq/credential.js` carries a rule it had to enforce in code
* because nothing else could: **a surface whose signature is verified on chain
* cannot be PQ.** A co-signer approval reaching `FinalRootAuthority` is checked
* by ECDSA/ERC-1271 in Solidity, so a PQ co-signer would produce approvals the
* contract cannot read, and the quorum would stop reaching threshold with
* nothing in any log naming the cause. `PQ_SURFACE` and `assertBackendVerified`
* exist to keep anyone from crossing that line by accident.
*
* Here the line is gone. The precompiles verify ML-DSA-87 and
* SLH-DSA-SHAKE-256s natively, so a quorum can be PQ *and* on chain, and
* "the backend says these four signatures verified" becomes "these four
* signatures verify, and any node re-derives that independently".
*
* ## Three rules, each closing a specific hole
*
* 1. **Keys come from the registry, never from calldata.** A key passed as an
* argument proves nothing — anyone with a keypair can sign under it. This is
* the difference between a 4-of-5 quorum and a 1-of-1 held by whoever built
* the transaction.
*
* 2. **Signers strictly ascending.** One comparison per entry rejects duplicates
* outright, so a single member cannot supply four approvals and satisfy a
* threshold of four. The alternative — an O(n²) seen-check — is the same
* guarantee with more ways to get it wrong.
*
* 3. **The digest binds chain id and verifying contract.** Without both, an
* approval collected for one contract is replayable against another with the
* same payload shape, and an approval from the test chain is replayable on
* the production one. These co-signers hold one key across environments.
*
* ## Which algorithm
*
* The stack splits its keys by hardness assumption, not by convenience:
* ML-DSA-87 (lattice) signs transactions, SLH-DSA-SHAKE-256s (hash-based) signs
* identity. Two families, so one cryptanalytic result cannot take both.
*
* So an action inherits the class of what it authorizes. Advancing a state root
* is operational and high-cadence: transaction class. Registering or revoking
* an identity is the thing the access class exists for. `ALG_ANY` is available
* and should be used sparingly — accepting either means a break in one family
* takes the quorum.
*
* An action that authorizes EXECUTION takes both: the ML-DSA-87 approval and a
* `seal`, an SLH-DSA-SHAKE-256s signature over the same digest by the member's
* `activeSeal` key. Neither family alone can then move funds, and the seal key
* is its own slot — never the access key — so the process that seals cannot
* also rotate the identity it seals for.
*
* Every digest binds an `anchorBlock`: the block at which the members read
* tree 1 to decide who is in the round. Binding it means every approval in a
* round was made against ONE roster view, and the window in `require_` means a
* view older than `ANCHOR_WINDOW` blocks is refused rather than honoured.
*
* The practical cost is worth stating: an SLH-DSA signature is 29,792 bytes, so
* a 4-of-5 access-class quorum is ~119 KB of calldata. That is affordable here
* only because this is our own chain. Do not carry this pattern to a chain
* where it is not.
*/
library FinalPqQuorum {
/// @notice ML-DSA-87 — FIPS 204. Algorithm ids are the FIPS numbers: the
/// same ids `FinalCertificate` and the backend registry use, and the numbers
/// the precompile addresses end in (`0x0204`).
uint8 internal constant ALG_ML_DSA_87 = 4;
/// @notice SLH-DSA-SHAKE-256s — FIPS 205 (`0x0205`).
uint8 internal constant ALG_SLH_DSA_SHAKE_256S = 5;
/// @notice Either scheme is acceptable for this action.
uint8 internal constant ALG_ANY = 0;
/// @notice How far behind the chain head an approval's anchor may sit.
/// @dev Members evaluate roster membership against tree 1 AT the anchor
/// block. 600 blocks is ten minutes at the chain's one-second cadence —
/// generous against a round that takes seconds, and short enough that a
/// roster rotated away is refused rather than counted.
uint64 internal constant ANCHOR_WINDOW = 600;
/// @dev Domain separator for every quorum digest. Distinct from any
/// EIP-712 domain in the stack: these are not typed-data signatures and
/// must not be confusable with one.
bytes32 internal constant DOMAIN_PQ_QUORUM = keccak256("FINAL_CHAIN_PQ_QUORUM_v01");
/// @notice One member's approval.
struct Approval {
/// The member's account, which is also the key it is looked up by.
address signer;
/// `ALG_ML_DSA_87` or `ALG_SLH_DSA_SHAKE_256S`.
uint8 algorithm;
/// Over the 32-byte digest from `digest()`, verbatim. Both schemes
/// hash internally, so the digest is not re-hashed before signing.
bytes signature;
/// SLH-DSA-SHAKE-256s over the same digest, by the member's `activeSeal`
/// key. Required where the action authorizes execution; empty otherwise.
bytes seal;
}
error ThresholdNotMet(uint256 valid, uint256 required);
error SignersNotAscending(address previous, address next);
error SignerLacksRole(address signer, uint256 roleMask);
error WrongAlgorithm(address signer, uint8 got, uint8 required);
error BadSignature(address signer, uint8 algorithm);
error BadSeal(address signer);
error AnchorAhead(uint64 anchorBlock, uint256 blockNumber);
error AnchorStale(uint64 anchorBlock, uint256 blockNumber);
error ThresholdIsZero();
/**
* @notice The message every member of this quorum signs.
* @param verifyingContract The contract consuming the approvals. Binding it
* stops an approval collected for one contract being replayed
* against another with the same payload shape.
* @param actionDomain What is being authorized — a per-action constant, so
* an approval for "advance the accounts tree" cannot be replayed as
* one for "revoke an identity".
* @param anchorBlock The Final Chain block the members read tree 1 at to
* decide the roster. Bound here so every approval in a round names
* the same view; checked against `ANCHOR_WINDOW` by `require_`.
* @param payloadDigest The action's own committed content. Callers MUST
* include a nonce or a monotonic counter in it; nothing here can
* tell a replay of round 7 from a fresh round 7.
*/
function digest(
address verifyingContract,
bytes32 actionDomain,
uint64 anchorBlock,
bytes32 payloadDigest
) internal view returns (bytes32) {
return keccak256(
abi.encode(
DOMAIN_PQ_QUORUM,
block.chainid,
verifyingContract,
actionDomain,
anchorBlock,
payloadDigest
)
);
}
/**
* @notice Reverts unless at least `threshold` distinct members holding
* `roleMask` have signed `quorumDigest`.
* @param registry Where public keys and roles come from. Not a parameter
* for flexibility — a parameter so the caller's own immutable
* registry address is what is used, rather than one from calldata.
* @param requiredAlgorithm `ALG_ANY` to accept either scheme.
* @param anchorBlock The anchor the digest was built over. Refused if it is
* ahead of this block or more than `ANCHOR_WINDOW` behind it.
* @param requireSeal Whether every approval must also carry a valid `seal`
* by the member's `activeSeal` key — the execution class.
* @return valid The number of approvals that verified, which is at least
* `threshold` if this returns at all.
*
* @dev Every failure reverts with the offending signer named. A quorum that
* silently skipped bad approvals and counted the rest would let a
* misconfigured co-signer sit broken indefinitely: the threshold would keep
* being met by the others and nothing would say one member had stopped
* contributing. That is exactly the failure this program has already had,
* in `fanOut`, where a per-chain advance failure was recorded and execution
* continued.
*/
function require_(
FinalIdentityRegistry registry,
Approval[] calldata approvals,
bytes32 quorumDigest,
uint256 roleMask,
uint256 threshold,
uint8 requiredAlgorithm,
uint64 anchorBlock,
bool requireSeal
) internal view returns (uint256 valid) {
if (threshold == 0) revert ThresholdIsZero();
if (anchorBlock > block.number) revert AnchorAhead(anchorBlock, block.number);
if (block.number - anchorBlock > ANCHOR_WINDOW) revert AnchorStale(anchorBlock, block.number);
bytes memory message = abi.encodePacked(quorumDigest);
address previous = address(0);
uint256 n = approvals.length;
for (uint256 i = 0; i < n; i++) {
Approval calldata a = approvals[i];
// Strictly ascending. `address(0)` as the initial value works
// because it can never be a registered signer.
if (a.signer <= previous) revert SignersNotAscending(previous, a.signer);
previous = a.signer;
if (!registry.hasRole(a.signer, roleMask)) revert SignerLacksRole(a.signer, roleMask);
if (requiredAlgorithm != ALG_ANY && a.algorithm != requiredAlgorithm) {
revert WrongAlgorithm(a.signer, a.algorithm, requiredAlgorithm);
}
if (!_verify(registry, a, message)) revert BadSignature(a.signer, a.algorithm);
if (requireSeal && !_verifySeal(registry, a, message)) revert BadSeal(a.signer);
valid++;
}
if (valid < threshold) revert ThresholdNotMet(valid, threshold);
}
/// @notice Non-reverting form, for views and for callers that want to
/// report rather than refuse.
function count(
FinalIdentityRegistry registry,
Approval[] calldata approvals,
bytes32 quorumDigest,
uint256 roleMask,
uint8 requiredAlgorithm,
uint64 anchorBlock,
bool requireSeal
) internal view returns (uint256 valid) {
if (anchorBlock > block.number || block.number - anchorBlock > ANCHOR_WINDOW) return 0;
bytes memory message = abi.encodePacked(quorumDigest);
address previous = address(0);
uint256 n = approvals.length;
for (uint256 i = 0; i < n; i++) {
Approval calldata a = approvals[i];
if (a.signer <= previous) return valid;
previous = a.signer;
if (!registry.hasRole(a.signer, roleMask)) continue;
if (requiredAlgorithm != ALG_ANY && a.algorithm != requiredAlgorithm) continue;
if (!_verify(registry, a, message)) continue;
if (requireSeal && !_verifySeal(registry, a, message)) continue;
valid++;
}
}
/// @dev The seal: SLH-DSA-SHAKE-256s by the member's `activeSeal` key over
/// the same digest. A member with no seal key on record cannot seal, and an
/// approval with no seal bytes is not one.
function _verifySeal(
FinalIdentityRegistry registry,
Approval calldata a,
bytes memory message
) private view returns (bool) {
bytes memory key = registry.activeSealKeyOf(a.signer);
if (key.length == 0 || a.seal.length == 0) return false;
return FinalChainPrecompiles.verifySlhDsa(key, message, a.seal);
}
function _verify(
FinalIdentityRegistry registry,
Approval calldata a,
bytes memory message
) private view returns (bool) {
// The LIVE pair, always. The recovery pair authorizes rotating this
// account's own credentials and NOTHING else — a quorum that accepted
// it would hand the recovery keys everyday authority, which is exactly
// the separation the two stages exist to draw.
if (a.algorithm == ALG_ML_DSA_87) {
return FinalChainPrecompiles.verifyMlDsa87(
registry.activeTransactionKeyOf(a.signer), message, a.signature
);
}
if (a.algorithm == ALG_SLH_DSA_SHAKE_256S) {
return FinalChainPrecompiles.verifySlhDsa(
registry.activeAccessKeyOf(a.signer), message, a.signature
);
}
// Any other id is a refusal, never a default — including the KEM ids
// (3, 7) and the reserved FN-DSA id (6), none of which is a signature
// scheme this quorum verifies.
return false;
}
}
abi
[
{
"type": "constructor",
"inputs": [
{
"name": "registry_",
"type": "address",
"internalType": "contract FinalIdentityRegistry"
},
{
"name": "admin_",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "ACTION_CONFIGURE",
"inputs": [],
"outputs": [
{
"name": "",
"type": "bytes32",
"internalType": "bytes32"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "ACTION_SEED",
"inputs": [],
"outputs": [
{
"name": "",
"type": "bytes32",
"internalType": "bytes32"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "TOTAL_SUPPLY",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "accountedSupply",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "admin",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "allocatedTo",
"inputs": [
{
"name": "",
"type": "bytes32",
"internalType": "bytes32"
}
],
"outputs": [
{
"name": "outstanding",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "epoch",
"type": "uint64",
"internalType": "uint64"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "configure",
"inputs": [
{
"name": "role",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "k",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "anchorBlock",
"type": "uint64",
"internalType": "uint64"
},
{
"name": "approvals",
"type": "tuple[]",
"internalType": "struct FinalPqQuorum.Approval[]",
"components": [
{
"name": "signer",
"type": "address",
"internalType": "address"
},
{
"name": "algorithm",
"type": "uint8",
"internalType": "uint8"
},
{
"name": "signature",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "seal",
"type": "bytes",
"internalType": "bytes"
}
]
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "consumedDespawn",
"inputs": [
{
"name": "",
"type": "bytes32",
"internalType": "bytes32"
},
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "bool",
"internalType": "bool"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "despawn",
"inputs": [
{
"name": "chainRef",
"type": "bytes32",
"internalType": "bytes32"
},
{
"name": "amount",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "originSeqId",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "anchorBlock",
"type": "uint64",
"internalType": "uint64"
},
{
"name": "approvals",
"type": "tuple[]",
"internalType": "struct FinalPqQuorum.Approval[]",
"components": [
{
"name": "signer",
"type": "address",
"internalType": "address"
},
{
"name": "algorithm",
"type": "uint8",
"internalType": "uint8"
},
{
"name": "signature",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "seal",
"type": "bytes",
"internalType": "bytes"
}
]
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "held",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "move",
"inputs": [
{
"name": "source",
"type": "bytes32",
"internalType": "bytes32"
},
{
"name": "target",
"type": "bytes32",
"internalType": "bytes32"
},
{
"name": "amount",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "anchorBlock",
"type": "uint64",
"internalType": "uint64"
},
{
"name": "approvals",
"type": "tuple[]",
"internalType": "struct FinalPqQuorum.Approval[]",
"components": [
{
"name": "signer",
"type": "address",
"internalType": "address"
},
{
"name": "algorithm",
"type": "uint8",
"internalType": "uint8"
},
{
"name": "signature",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "seal",
"type": "bytes",
"internalType": "bytes"
}
]
}
],
"outputs": [
{
"name": "seq",
"type": "uint64",
"internalType": "uint64"
}
],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "nonce",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint64",
"internalType": "uint64"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "outstandingOn",
"inputs": [
{
"name": "chainRef",
"type": "bytes32",
"internalType": "bytes32"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "publisherRole",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "registry",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "contract FinalIdentityRegistry"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "seal",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "seed",
"inputs": [
{
"name": "refs",
"type": "bytes32[]",
"internalType": "bytes32[]"
},
{
"name": "outstanding",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "epochs",
"type": "uint64[]",
"internalType": "uint64[]"
},
{
"name": "despawnRefs",
"type": "bytes32[]",
"internalType": "bytes32[]"
},
{
"name": "despawnSeqs",
"type": "uint256[]",
"internalType": "uint256[]"
},
{
"name": "nonce_",
"type": "uint64",
"internalType": "uint64"
},
{
"name": "anchorBlock",
"type": "uint64",
"internalType": "uint64"
},
{
"name": "approvals",
"type": "tuple[]",
"internalType": "struct FinalPqQuorum.Approval[]",
"components": [
{
"name": "signer",
"type": "address",
"internalType": "address"
},
{
"name": "algorithm",
"type": "uint8",
"internalType": "uint8"
},
{
"name": "signature",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "seal",
"type": "bytes",
"internalType": "bytes"
}
]
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "spawn",
"inputs": [
{
"name": "chainRef",
"type": "bytes32",
"internalType": "bytes32"
},
{
"name": "amount",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "anchorBlock",
"type": "uint64",
"internalType": "uint64"
},
{
"name": "approvals",
"type": "tuple[]",
"internalType": "struct FinalPqQuorum.Approval[]",
"components": [
{
"name": "signer",
"type": "address",
"internalType": "address"
},
{
"name": "algorithm",
"type": "uint8",
"internalType": "uint8"
},
{
"name": "signature",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "seal",
"type": "bytes",
"internalType": "bytes"
}
]
}
],
"outputs": [
{
"name": "seq",
"type": "uint64",
"internalType": "uint64"
}
],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "threshold",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "totalAllocated",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "event",
"name": "Despawned",
"inputs": [
{
"name": "chainRef",
"type": "bytes32",
"indexed": true,
"internalType": "bytes32"
},
{
"name": "amount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "outstanding",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "epoch",
"type": "uint64",
"indexed": false,
"internalType": "uint64"
},
{
"name": "originSeqId",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"type": "event",
"name": "Moved",
"inputs": [
{
"name": "source",
"type": "bytes32",
"indexed": true,
"internalType": "bytes32"
},
{
"name": "target",
"type": "bytes32",
"indexed": true,
"internalType": "bytes32"
},
{
"name": "amount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "sourceOutstanding",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "targetOutstanding",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "seq",
"type": "uint64",
"indexed": false,
"internalType": "uint64"
}
],
"anonymous": false
},
{
"type": "event",
"name": "Sealed",
"inputs": [],
"anonymous": false
},
{
"type": "event",
"name": "Seeded",
"inputs": [
{
"name": "allocations",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "despawns",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "nonce",
"type": "uint64",
"indexed": false,
"internalType": "uint64"
}
],
"anonymous": false
},
{
"type": "event",
"name": "Spawned",
"inputs": [
{
"name": "chainRef",
"type": "bytes32",
"indexed": true,
"internalType": "bytes32"
},
{
"name": "amount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "outstanding",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "epoch",
"type": "uint64",
"indexed": false,
"internalType": "uint64"
},
{
"name": "seq",
"type": "uint64",
"indexed": false,
"internalType": "uint64"
}
],
"anonymous": false
},
{
"type": "event",
"name": "SupplyConfigured",
"inputs": [
{
"name": "role",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "threshold",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"type": "error",
"name": "AlreadyConsumed",
"inputs": [
{
"name": "chainRef",
"type": "bytes32",
"internalType": "bytes32"
},
{
"name": "originSeqId",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"type": "error",
"name": "AnchorAhead",
"inputs": [
{
"name": "anchorBlock",
"type": "uint64",
"internalType": "uint64"
},
{
"name": "blockNumber",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"type": "error",
"name": "AnchorStale",
"inputs": [
{
"name": "anchorBlock",
"type": "uint64",
"internalType": "uint64"
},
{
"name": "blockNumber",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"type": "error",
"name": "BadSeal",
"inputs": [
{
"name": "signer",
"type": "address",
"internalType": "address"
}
]
},
{
"type": "error",
"name": "BadSignature",
"inputs": [
{
"name": "signer",
"type": "address",
"internalType": "address"
},
{
"name": "algorithm",
"type": "uint8",
"internalType": "uint8"
}
]
},
{
"type": "error",
"name": "InsufficientAllocation",
"inputs": [
{
"name": "chainRef",
"type": "bytes32",
"internalType": "bytes32"
},
{
"name": "want",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "have",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"type": "error",
"name": "InsufficientHeld",
"inputs": [
{
"name": "want",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "have",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"type": "error",
"name": "InvalidMove",
"inputs": [
{
"name": "source",
"type": "bytes32",
"internalType": "bytes32"
},
{
"name": "target",
"type": "bytes32",
"internalType": "bytes32"
}
]
},
{
"type": "error",
"name": "NotAdmin",
"inputs": [
{
"name": "caller",
"type": "address",
"internalType": "address"
}
]
},
{
"type": "error",
"name": "NotConfigured",
"inputs": []
},
{
"type": "error",
"name": "NotFresh",
"inputs": []
},
{
"type": "error",
"name": "SeedRefRepeated",
"inputs": [
{
"name": "chainRef",
"type": "bytes32",
"internalType": "bytes32"
}
]
},
{
"type": "error",
"name": "SeedShapeMismatch",
"inputs": []
},
{
"type": "error",
"name": "SignerLacksRole",
"inputs": [
{
"name": "signer",
"type": "address",
"internalType": "address"
},
{
"name": "roleMask",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"type": "error",
"name": "SignersNotAscending",
"inputs": [
{
"name": "previous",
"type": "address",
"internalType": "address"
},
{
"name": "next",
"type": "address",
"internalType": "address"
}
]
},
{
"type": "error",
"name": "SupplyInvariantBroken",
"inputs": [
{
"name": "held",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "allocated",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"type": "error",
"name": "ThresholdIsZero",
"inputs": []
},
{
"type": "error",
"name": "ThresholdNotMet",
"inputs": [
{
"name": "valid",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "required",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"type": "error",
"name": "ThresholdUnreachable",
"inputs": [
{
"name": "live",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "wanted",
"type": "uint256",
"internalType": "uint256"
}
]
},
{
"type": "error",
"name": "WrongAlgorithm",
"inputs": [
{
"name": "signer",
"type": "address",
"internalType": "address"
},
{
"name": "got",
"type": "uint8",
"internalType": "uint8"
},
{
"name": "required",
"type": "uint8",
"internalType": "uint8"
}
]
},
{
"type": "error",
"name": "ZeroAmount",
"inputs": []
}
]read contract
bytecode · 7,635 bytes
0x6101a0806040526004361015610013575f80fd5b5f610160525f3560e01c9081620b82b51461158e5750806307a96b5c1461133d5780633fb27b85146112cf57806342cde4e8146112b257806345f7f2491461129557806372f56b2c1461125b5780637b103999146112175780638d0de241146111db5780638eae91b2146111b2578063902d55a51461118d57806394bc4e9614610eab578063a1aab18c146106cc578063a285aed7146106ac578063a2c7376c146104b8578063affed0e01461048f578063b19f480514610452578063e1c783cb14610422578063e96b949114610151578063f4e885db146101315763f851a440146100fd575f80fd5b3461012a576101605136600319011261012a5761016051546040516001600160a01b039091168152602090f35b6101605180fd5b3461012a576101605136600319011261012a576020600154604051908152f35b3461012a5760a036600319011261012a576044356004356024356101736115c4565b916084356001600160401b03811161012a576101939036906004016115f0565b939060025491821561040d5786156103f857831580156103f0575b80156103e7575b6103c9578361016051526004602052604061016051209283548089116103a95750926080926102ef602099937f918413a673b69ea329c13b81535c07cd4e55e8544a26871a6f0d841f203af09996600654936001600160401b0385169b8c6040518f81019182528c60408201528d6060820152898b8201528a815261023b60a082611620565b51902061016051506040518f8101917fd850f5df47b124511e8e6ec99cf1a0beaf7c6237eff0a31305ce53d85f31267583524660408301523060608301527f5315ade0aa736cdc5532fa19a1ed12e3ce89b6ad07040b14bac780938e50423b8c8301526001600160401b03871660a083015260c082015260c081526102c160e082611620565b51902090600154927f000000000000000000000000a2e71fc2fb02d1ce93aa958e56cab83d26f3bfa6611788565b506001600160401b0361030189611655565b16906001600160401b03191617600655856101605152600488526040610160512090828154038155828254018255600181016001600160401b0361034781835416611655565b166001600160401b0319825416179055600182016001600160401b0361036f81835416611655565b166001600160401b03198254161790556103876119fa565b54905490604051928352888301526040820152856060820152a3604051908152f35b8886637c06acb760e11b6101605152600452602452604452606461016051fd5b50505063108b161760e01b6101605152600452602452604461016051fd5b508484146101b5565b5084156101ae565b631f2a200560e01b6101605152600461016051fd5b63d311bc3960e01b6101605152600461016051fd5b3461012a57602036600319011261012a576004356101605152600460205260206040610160512054604051908152f35b3461012a576101605136600319011261012a5760206040517fbc5858e168b959a61a8fb2d7957ef31dbed683a362770ca030e5d772cc44e0688152f35b3461012a576101605136600319011261012a5760206001600160401b0360065416604051908152f35b3461012a57608036600319011261012a576004356024356104d76115da565b916064356001600160401b03811161012a576104f79036906004016115f0565b929060025494851561040d5782156103f8576003549586841161068f57956080926105fa7f4565741fc5c16ad3a3a3fbbf4311621df9850edf4097f549079a6855d21331359593602099600654936001600160401b0385169a6040518d8101908d82528c6040820152896060820152606081526105748b82611620565b51902061016051506040518e8101917fd850f5df47b124511e8e6ec99cf1a0beaf7c6237eff0a31305ce53d85f31267583524660408301523060608301527fef06d5e846d5c9e7b4cf0eb3e3b66d716af68a3cea05cd7bc7743bbc177405228c8301526001600160401b03871660a083015260c082015260c081526102c160e082611620565b506001600160401b0361060c88611655565b16906001600160401b03191617600655846101605152600487528160406101605120910360035581815401815581600554016005556001600160401b0360018201918161065b81855416611655565b16821984541617835561066c6119fa565b5491541690604051928352878301526040820152846060820152a2604051908152f35b8684631125005160e21b6101605152600452602452604461016051fd5b3461012a576101605136600319011261012a576020600354604051908152f35b3461012a5761010036600319011261012a576004356001600160401b03811161012a576106fd9036906004016115f0565b610180526024356001600160401b03811161012a576107209036906004016115f0565b6044929192356001600160401b03811161012a576107429036906004016115f0565b60a0526080526064356001600160401b03811161012a576107679036906004016115f0565b61012052610100526084356001600160401b03811161012a5761078e9036906004016115f0565b60c05260e05260a4356101408190526001600160401b038116900361012a5760c4356001600160401b038116810361012a5760e4356001600160401b03811161012a576107df9036906004016115f0565b6040516328305db160e21b81529091906020816004817f000000000000000000000000a2e71fc2fb02d1ce93aa958e56cab83d26f3bfa66001600160a01b03165afa908115610cf3576101605191610e7c575b508015610dd7575b610b22575b5050506001600160401b036006541615801590610b17575b610b0257806101805114801590610af3575b610abc5760c0516101205103610abc576101605192839291905b6101805184106109e057846a52b7d2dcc80cd2e400000081116109b957806005556a52b7d2dcc80cd2e4000000036a52b7d2dcc80cd2e4000000811161099f57600355610160515b61012051811061094a576001600160401b0361014051166001600160401b031960065416176006556108fb6119fa565b7fb04da588109787f2e1bce4cc15cc0e414cae26034cea4902695311f75568bf8760606040516101805181526101205160208201526001600160401b0361014051166040820152a16101605180f35b8061095e6001926101205161010051611721565b35610160515260076020526040610160512061097f8260c05160e051611721565b356101605152602052604061016051208260ff19825416179055016108cb565b634e487b7160e01b61016051526011600452602461016051fd5b631125005160e21b61016051526004526a52b7d2dcc80cd2e4000000602452604461016051fd5b909192936109f2856101805186611721565b35158015610ad1575b610abc57610a0d856101805186611721565b35610160515260046020526040610160512060018101906001600160401b03825416610a945791610a8a91600193610a46898888611721565b3590556001600160401b03610a68610a638a60a051608051611721565b611745565b166001600160401b0319825416179055610a83878686611721565b3590611687565b9401929190610883565b610aa387876101805190611721565b3563724ac17360e01b6101605152600452602461016051fd5b63200ff7d760e11b6101605152600461016051fd5b506001600160401b03610aec610a638760a051608051611721565b16156109fb565b5060a051610180511415610869565b63dc63d81f60e01b6101605152600461016051fd5b506005541515610857565b60405160c060208201526020610b55610b4260e08401610180518a6116fd565b838103601f19016040850152878a6116fd565b601f1983820301606084015260a05181520181608051610160515b60a0518110610da5575050610bb5610b9e610bd593601f1984820301608085015261012051610100516116fd565b828103601f190160a084015260c05160e0516116fd565b6001600160401b03610140511660c083015203601f198101835282611620565b80516020909101206001600160a01b037f000000000000000000000000a2e71fc2fb02d1ce93aa958e56cab83d26f3bfa6163b1561012a5782906001600160401b03604051956322f3f44760e11b8752610160515060848701927f08296c4851c7aca93c422c73902d61d179ed1bf52cf0ed257e6d096b9a8bb85160048901526024880152166044860152608060648601525260a4830160a060048460051b86010101928261016051905b828210610d0157505061016051938593508390039150829050837f000000000000000000000000a2e71fc2fb02d1ce93aa958e56cab83d26f3bfa66001600160a01b03165af18015610cf357610cd8575b808061083f565b61016051610ce591611620565b6101605161012a5783610cd1565b6040513d61016051823e3d90fd5b9091929394609f19600319888303010185528535607e198336030181121561012a57820180356001600160a01b0381169081900361012a57825260208101359160ff831680930361012a57610d98602092826001958580950152610d8a610d7f610d6e6040850185611694565b6080604086015260808501916116c5565b926060810190611694565b9160608185039101526116c5565b9701950193920190610c80565b91509161016051508235906001600160401b03821680920361012a576020816001938293520193019101908391610b70565b5060405163f5778b0360e01b81526020816004817f000000000000000000000000a2e71fc2fb02d1ce93aa958e56cab83d26f3bfa66001600160a01b03165afa908115610cf3576101605191610e3a575b506001600160a01b031633141561083a565b90506020813d602011610e74575b81610e5560209383611620565b8101031261012a57516001600160a01b038116810361012a5787610e28565b3d9150610e48565b610e9e915060203d602011610ea4575b610e968183611620565b8101906116e5565b87610832565b503d610e8c565b3461118957608036600319011261118957602435600435610eca6115da565b6064356001600160401b03811161118957610ee99036906004016115f0565b5f546001600160a01b03163303610ff7575b50505081610f43575b807f43c4ef2494de90aa2f24830e48f3dc8579dec67c48d59b2ffba50c125576d4c4926040926001558060025582519182526020820152a16101605180f35b60405163342f616360e01b8152600481018290526020816024817f000000000000000000000000a2e71fc2fb02d1ce93aa958e56cab83d26f3bfa66001600160a01b03165afa908115610cf3576101605191610fc5575b50828110610fa85750610f04565b9050633770da3360e11b6101605152600452602452604461016051fd5b90506020813d602011610fef575b81610fe060209383611620565b8101031261012a575183610f9a565b3d9150610fd3565b60408051602081018681528183018890529181527f000000000000000000000000a2e71fc2fb02d1ce93aa958e56cab83d26f3bfa66001600160a01b0316939190611043606082611620565b519020833b156111895790826001600160401b039593926040519687956322f3f44760e11b875260848701927fbc5858e168b959a61a8fb2d7957ef31dbed683a362770ca030e5d772cc44e06860048901526024880152166044860152608060648601525260a4830160a060048460051b8601010192825f90607e19813603015b83831061110f5750505050505091815f818582965003925af18015611104576110ef575b8080610efb565b5f6110f991611620565b5f61016052826110e8565b6040513d5f823e3d90fd5b60a3198a88030185529496509294919390929186358281121561118957830180356001600160a01b0381169081900361118957825260208101359160ff831680930361118957611177602092826001958580950152610d8a610d7f610d6e6040850185611694565b980196019301909188969594926110c4565b5f80fd5b34611189575f3660031901126111895760206040516a52b7d2dcc80cd2e40000008152f35b34611189575f3660031901126111895760206111d360035460055490611687565b604051908152f35b34611189576020366003190112611189576004355f5260046020526040805f206001600160401b03600182549201541682519182526020820152f35b34611189575f366003190112611189576040517f000000000000000000000000a2e71fc2fb02d1ce93aa958e56cab83d26f3bfa66001600160a01b03168152602090f35b34611189575f3660031901126111895760206040517f08296c4851c7aca93c422c73902d61d179ed1bf52cf0ed257e6d096b9a8bb8518152f35b34611189575f366003190112611189576020600554604051908152f35b34611189575f366003190112611189576020600254604051908152f35b34611189575f366003190112611189575f546001600160a01b038116330361132a576bffffffffffffffffffffffff60a01b165f557f1b2d71eb44f882534bf4e86f940c56ccc869ffb927e2bab86561de93950c22165f80a1005b630bd4212160e11b5f523360045260245ffd5b346111895760a03660031901126111895760043560243560443561135f6115c4565b6084356001600160401b0381116111895761137e9036906004016115f0565b9091600254801561157f57851561157057865f52600760205260405f20855f5260205260ff60405f20541661155957865f52600460205260405f2093845480881161153f57506114b0886114aa7f3ef380598f06b01333350e61cefa066c10a2088a64ad65aadd22eda04b972b8999979560809997956001600160401b03956006549787891695604051602081019188835260408201528d60608201528c8f8201528e815261142e60a082611620565b51902060405160208101917fd850f5df47b124511e8e6ec99cf1a0beaf7c6237eff0a31305ce53d85f31267583524660408301523060608301528f7f07e27cdd90594a3caa105e64724b3ff44d247017420d1a3df2cc49fa10cdf0f5908301528a871660a083015260c082015260c081526102c160e082611620565b50611655565b16906001600160401b03191617600655855f52600760205260405f20825f5260205260405f20600160ff19825416179055828154038155826005540360055582600354016003556001600160401b0360018201918161151181855416611655565b1682198454161783556115226119fa565b5491541690604051938452602084015260408301526060820152a2005b8789637c06acb760e11b5f5260045260245260445260645ffd5b8487630dd4fdfd60e21b5f5260045260245260445ffd5b631f2a200560e01b5f5260045ffd5b63d311bc3960e01b5f5260045ffd5b34611189576040366003190112611189576020906004355f526007825260405f206024355f52825260ff60405f20541615158152f35b606435906001600160401b038216820361118957565b604435906001600160401b038216820361118957565b9181601f84011215611189578235916001600160401b038311611189576020808501948460051b01011161118957565b90601f801991011681019081106001600160401b0382111761164157604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b036001911601906001600160401b03821161167357565b634e487b7160e01b5f52601160045260245ffd5b9190820180921161167357565b9035601e19823603018112156111895701602081359101916001600160401b03821161118957813603831361118957565b908060209392818452848401375f828201840152601f01601f1916010190565b90816020910312611189575180151581036111895790565b81835290916001600160fb1b0383116111895760209260051b809284830137010190565b91908110156117315760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160401b03811681036111895790565b9190820391821161167357565b356001600160a01b03811681036111895790565b3560ff811681036111895790565b94939195965f9785156119eb576001600160401b03164381116119d5576102586117b28243611759565b116119bf5750604051936020850152602084526117d0604085611620565b5f945f985b888a1015611995578960051b840135607e1985360301811215611189578401966117fe88611766565b6001600160a01b039182169116811015611969575061181c87611766565b9661185d60208761182c84611766565b604051632e4bfa5160e11b81526001600160a01b039091166004820152602481019190915291829081906044820190565b03816001600160a01b038e165afa908115611104575f9161194b575b5015611924576020810190600460ff6118918461177a565b16036118f1576118a288828c611b1a565b156118bd5750505f198114611673576001998a0199016117d5565b906118d26118cc60ff93611766565b9161177a565b9063bbf82ba360e01b5f5260018060a01b03166004521660245260445ffd5b906119006118cc60ff93611766565b9063587548c360e11b5f5260018060a01b031660045216602452600460445260645ffd5b61192e8691611766565b63ae8bb03960e01b5f5260018060a01b031660045260245260445ffd5b611963915060203d8111610ea457610e968183611620565b5f611879565b61197288611766565b6311641feb60e21b5f9081526004929092526001600160a01b0316602452604490fd5b985095509550505050508083106119a95750565b826305bc216760e51b5f5260045260245260445ffd5b630ed38fd160e41b5f526004524360245260445ffd5b637b51505560e01b5f526004524360245260445ffd5b631fc460bf60e11b5f5260045ffd5b600354600554906a52b7d2dcc80cd2e4000000611a178383611687565b03611a20575050565b63e0724a2b60e01b5f5260045260245260445ffd5b6001600160401b03811161164157601f01601f191660200190565b602081830312611189578051906001600160401b038211611189570181601f8201121561118957805190611a8382611a35565b92611a916040519485611620565b8284526020838301011161118957815f9260208093018386015e8301015290565b903590601e198136030182121561118957018035906001600160401b0382116111895760200191813603831361118957565b929192611af082611a35565b91611afe6040519384611620565b829481845281830111611189578281602093845f960137010152565b9160208201600460ff611b2c8361177a565b1614611bde5760ff611b3f60059261177a565b1614611b4c575050505f90565b5f611b5683611766565b604051639e5adaeb60e01b81526001600160a01b0391821660048201529485916024918391165afa91821561110457611baf935f93611bb2575b50611ba2816040611ba9930190611ab2565b3691611ae4565b91611d4f565b90565b611ba9919350611bd6611ba2913d805f833e611bce8183611620565b810190611a50565b939150611b90565b505f611be983611766565b60405163b7af85d760e01b81526001600160a01b0391821660048201529485916024918391165afa91821561110457611baf935f93611c3b575b50611ba2816040611c35930190611ab2565b91611c5f565b611c35919350611c57611ba2913d805f833e611bce8183611620565b939150611c23565b610a20815114801590611d42575b611d3b576020611cc05f948286958160405195869481808701998051918291018b5e8601908282018b8152815193849201905e010190878252805192839101825e0185815203601f198101835282611620565b51906102045afa3d15611d34573d611cd781611a35565b90611ce56040519283611620565b81523d5f602083013e5b81611d28575b81611cfe575090565b9050602081519101519060208110611d17575b50151590565b5f199060200360031b1b165f611d11565b80516020149150611cf5565b6060611cef565b5050505f90565b5061121383511415611c6d565b6040815114801590611dc6575b611d3b576020611daf5f948286958160405195869481808701998051918291018b5e8601908282018b8152815193849201905e010190878252805192839101825e0185815203601f198101835282611620565b51906102055afa3d15611d34573d611cd781611a35565b5061746083511415611d5c56
No CBOR metadata tail — this bytecode was built with cbor_metadata off, the setting our own contracts pin for CREATE2 address invariance.
disassembly (first 4,000 ops)
| pc | op | operand |
|---|---|---|
| 0000 | PUSH2 | 0x01a0 |
| 0003 | DUP1 | |
| 0004 | PUSH1 | 0x40 |
| 0006 | MSTORE | |
| 0007 | PUSH1 | 0x04 |
| 0009 | CALLDATASIZE | |
| 000a | LT | |
| 000b | ISZERO | |
| 000c | PUSH2 | 0x0013 |
| 000f | JUMPI | |
| 0010 | PUSH0 | |
| 0011 | DUP1 | |
| 0012 | REVERT | |
| 0013 | JUMPDEST | |
| 0014 | PUSH0 | |
| 0015 | PUSH2 | 0x0160 |
| 0018 | MSTORE | |
| 0019 | PUSH0 | |
| 001a | CALLDATALOAD | |
| 001b | PUSH1 | 0xe0 |
| 001d | SHR | |
| 001e | SWAP1 | |
| 001f | DUP2 | |
| 0020 | PUSH3 | 0x0b82b5 |
| 0024 | EQ | |
| 0025 | PUSH2 | 0x158e |
| 0028 | JUMPI | |
| 0029 | POP | |
| 002a | DUP1 | |
| 002b | PUSH4 | 0x07a96b5c |
| 0030 | EQ | |
| 0031 | PUSH2 | 0x133d |
| 0034 | JUMPI | |
| 0035 | DUP1 | |
| 0036 | PUSH4 | 0x3fb27b85 |
| 003b | EQ | |
| 003c | PUSH2 | 0x12cf |
| 003f | JUMPI | |
| 0040 | DUP1 | |
| 0041 | PUSH4 | 0x42cde4e8 |
| 0046 | EQ | |
| 0047 | PUSH2 | 0x12b2 |
| 004a | JUMPI | |
| 004b | DUP1 | |
| 004c | PUSH4 | 0x45f7f249 |
| 0051 | EQ | |
| 0052 | PUSH2 | 0x1295 |
| 0055 | JUMPI | |
| 0056 | DUP1 | |
| 0057 | PUSH4 | 0x72f56b2c |
| 005c | EQ | |
| 005d | PUSH2 | 0x125b |
| 0060 | JUMPI | |
| 0061 | DUP1 | |
| 0062 | PUSH4 | 0x7b103999 |
| 0067 | EQ | |
| 0068 | PUSH2 | 0x1217 |
| 006b | JUMPI | |
| 006c | DUP1 | |
| 006d | PUSH4 | 0x8d0de241 |
| 0072 | EQ | |
| 0073 | PUSH2 | 0x11db |
| 0076 | JUMPI | |
| 0077 | DUP1 | |
| 0078 | PUSH4 | 0x8eae91b2 |
| 007d | EQ | |
| 007e | PUSH2 | 0x11b2 |
| 0081 | JUMPI | |
| 0082 | DUP1 | |
| 0083 | PUSH4 | 0x902d55a5 |
| 0088 | EQ | |
| 0089 | PUSH2 | 0x118d |
| 008c | JUMPI | |
| 008d | DUP1 | |
| 008e | PUSH4 | 0x94bc4e96 |
| 0093 | EQ | |
| 0094 | PUSH2 | 0x0eab |
| 0097 | JUMPI | |
| 0098 | DUP1 | |
| 0099 | PUSH4 | 0xa1aab18c |
| 009e | EQ | |
| 009f | PUSH2 | 0x06cc |
| 00a2 | JUMPI | |
| 00a3 | DUP1 | |
| 00a4 | PUSH4 | 0xa285aed7 |
| 00a9 | EQ | |
| 00aa | PUSH2 | 0x06ac |
| 00ad | JUMPI | |
| 00ae | DUP1 | |
| 00af | PUSH4 | 0xa2c7376c |
| 00b4 | EQ | |
| 00b5 | PUSH2 | 0x04b8 |
| 00b8 | JUMPI | |
| 00b9 | DUP1 | |
| 00ba | PUSH4 | 0xaffed0e0 |
| 00bf | EQ | |
| 00c0 | PUSH2 | 0x048f |
| 00c3 | JUMPI | |
| 00c4 | DUP1 | |
| 00c5 | PUSH4 | 0xb19f4805 |
| 00ca | EQ | |
| 00cb | PUSH2 | 0x0452 |
| 00ce | JUMPI | |
| 00cf | DUP1 | |
| 00d0 | PUSH4 | 0xe1c783cb |
| 00d5 | EQ | |
| 00d6 | PUSH2 | 0x0422 |
| 00d9 | JUMPI | |
| 00da | DUP1 | |
| 00db | PUSH4 | 0xe96b9491 |
| 00e0 | EQ | |
| 00e1 | PUSH2 | 0x0151 |
| 00e4 | JUMPI | |
| 00e5 | DUP1 | |
| 00e6 | PUSH4 | 0xf4e885db |
| 00eb | EQ | |
| 00ec | PUSH2 | 0x0131 |
| 00ef | JUMPI | |
| 00f0 | PUSH4 | 0xf851a440 |
| 00f5 | EQ | |
| 00f6 | PUSH2 | 0x00fd |
| 00f9 | JUMPI | |
| 00fa | PUSH0 | |
| 00fb | DUP1 | |
| 00fc | REVERT | |
| 00fd | JUMPDEST | |
| 00fe | CALLVALUE | |
| 00ff | PUSH2 | 0x012a |
| 0102 | JUMPI | |
| 0103 | PUSH2 | 0x0160 |
| 0106 | MLOAD | |
| 0107 | CALLDATASIZE | |
| 0108 | PUSH1 | 0x03 |
| 010a | NOT | |
| 010b | ADD | |
| 010c | SLT | |
| 010d | PUSH2 | 0x012a |
| 0110 | JUMPI | |
| 0111 | PUSH2 | 0x0160 |
| 0114 | MLOAD | |
| 0115 | SLOAD | |
| 0116 | PUSH1 | 0x40 |
| 0118 | MLOAD | |
| 0119 | PUSH1 | 0x01 |
| 011b | PUSH1 | 0x01 |
| 011d | PUSH1 | 0xa0 |
| 011f | SHL | |
| 0120 | SUB | |
| 0121 | SWAP1 | |
| 0122 | SWAP2 | |
| 0123 | AND | |
| 0124 | DUP2 | |
| 0125 | MSTORE | |
| 0126 | PUSH1 | 0x20 |
| 0128 | SWAP1 | |
| 0129 | RETURN | |
| 012a | JUMPDEST | |
| 012b | PUSH2 | 0x0160 |
| 012e | MLOAD | |
| 012f | DUP1 | |
| 0130 | REVERT | |
| 0131 | JUMPDEST | |
| 0132 | CALLVALUE | |
| 0133 | PUSH2 | 0x012a |
| 0136 | JUMPI | |
| 0137 | PUSH2 | 0x0160 |
| 013a | MLOAD | |
| 013b | CALLDATASIZE | |
| 013c | PUSH1 | 0x03 |
| 013e | NOT | |
| 013f | ADD | |
| 0140 | SLT | |
| 0141 | PUSH2 | 0x012a |
| 0144 | JUMPI | |
| 0145 | PUSH1 | 0x20 |
| 0147 | PUSH1 | 0x01 |
| 0149 | SLOAD | |
| 014a | PUSH1 | 0x40 |
| 014c | MLOAD | |
| 014d | SWAP1 | |
| 014e | DUP2 | |
| 014f | MSTORE | |
| 0150 | RETURN | |
| 0151 | JUMPDEST | |
| 0152 | CALLVALUE | |
| 0153 | PUSH2 | 0x012a |
| 0156 | JUMPI | |
| 0157 | PUSH1 | 0xa0 |
| 0159 | CALLDATASIZE | |
| 015a | PUSH1 | 0x03 |
| 015c | NOT | |
| 015d | ADD | |
| 015e | SLT | |
| 015f | PUSH2 | 0x012a |
| 0162 | JUMPI | |
| 0163 | PUSH1 | 0x44 |
| 0165 | CALLDATALOAD | |
| 0166 | PUSH1 | 0x04 |
| 0168 | CALLDATALOAD | |
| 0169 | PUSH1 | 0x24 |
| 016b | CALLDATALOAD | |
| 016c | PUSH2 | 0x0173 |
| 016f | PUSH2 | 0x15c4 |
| 0172 | JUMP | |
| 0173 | JUMPDEST | |
| 0174 | SWAP2 | |
| 0175 | PUSH1 | 0x84 |
| 0177 | CALLDATALOAD | |
| 0178 | PUSH1 | 0x01 |
| 017a | PUSH1 | 0x01 |
| 017c | PUSH1 | 0x40 |
| 017e | SHL | |
| 017f | SUB | |
| 0180 | DUP2 | |
| 0181 | GT | |
| 0182 | PUSH2 | 0x012a |
| 0185 | JUMPI | |
| 0186 | PUSH2 | 0x0193 |
| 0189 | SWAP1 | |
| 018a | CALLDATASIZE | |
| 018b | SWAP1 | |
| 018c | PUSH1 | 0x04 |
| 018e | ADD | |
| 018f | PUSH2 | 0x15f0 |
| 0192 | JUMP | |
| 0193 | JUMPDEST | |
| 0194 | SWAP4 | |
| 0195 | SWAP1 | |
| 0196 | PUSH1 | 0x02 |
| 0198 | SLOAD | |
| 0199 | SWAP2 | |
| 019a | DUP3 | |
| 019b | ISZERO | |
| 019c | PUSH2 | 0x040d |
| 019f | JUMPI | |
| 01a0 | DUP7 | |
| 01a1 | ISZERO | |
| 01a2 | PUSH2 | 0x03f8 |
| 01a5 | JUMPI | |
| 01a6 | DUP4 | |
| 01a7 | ISZERO | |
| 01a8 | DUP1 | |
| 01a9 | ISZERO | |
| 01aa | PUSH2 | 0x03f0 |
| 01ad | JUMPI | |
| 01ae | JUMPDEST | |
| 01af | DUP1 | |
| 01b0 | ISZERO | |
| 01b1 | PUSH2 | 0x03e7 |
| 01b4 | JUMPI | |
| 01b5 | JUMPDEST | |
| 01b6 | PUSH2 | 0x03c9 |
| 01b9 | JUMPI | |
| 01ba | DUP4 | |
| 01bb | PUSH2 | 0x0160 |
| 01be | MLOAD | |
| 01bf | MSTORE | |
| 01c0 | PUSH1 | 0x04 |
| 01c2 | PUSH1 | 0x20 |
| 01c4 | MSTORE | |
| 01c5 | PUSH1 | 0x40 |
| 01c7 | PUSH2 | 0x0160 |
| 01ca | MLOAD | |
| 01cb | KECCAK256 | |
| 01cc | SWAP3 | |
| 01cd | DUP4 | |
| 01ce | SLOAD | |
| 01cf | DUP1 | |
| 01d0 | DUP10 | |
| 01d1 | GT | |
| 01d2 | PUSH2 | 0x03a9 |
| 01d5 | JUMPI | |
| 01d6 | POP | |
| 01d7 | SWAP3 | |
| 01d8 | PUSH1 | 0x80 |
| 01da | SWAP3 | |
| 01db | PUSH2 | 0x02ef |
| 01de | PUSH1 | 0x20 |
| 01e0 | SWAP10 | |
| 01e1 | SWAP4 | |
| 01e2 | PUSH32 | 0x918413a673b69ea329c13b81535c07cd4e55e8544a26871a6f0d841f203af099 |
| 0203 | SWAP7 | |
| 0204 | PUSH1 | 0x06 |
| 0206 | SLOAD | |
| 0207 | SWAP4 | |
| 0208 | PUSH1 | 0x01 |
| 020a | PUSH1 | 0x01 |
| 020c | PUSH1 | 0x40 |
| 020e | SHL | |
| 020f | SUB | |
| 0210 | DUP6 | |
| 0211 | AND | |
| 0212 | SWAP12 | |
| 0213 | DUP13 | |
| 0214 | PUSH1 | 0x40 |
| 0216 | MLOAD | |
| 0217 | DUP16 | |
| 0218 | DUP2 | |
| 0219 | ADD | |
| 021a | SWAP2 | |
| 021b | DUP3 | |
| 021c | MSTORE | |
| 021d | DUP13 | |
| 021e | PUSH1 | 0x40 |
| 0220 | DUP3 | |
| 0221 | ADD | |
| 0222 | MSTORE | |
| 0223 | DUP14 | |
| 0224 | PUSH1 | 0x60 |
| 0226 | DUP3 | |
| 0227 | ADD | |
| 0228 | MSTORE | |
| 0229 | DUP10 | |
| 022a | DUP12 | |
| 022b | DUP3 | |
| 022c | ADD | |
| 022d | MSTORE | |
| 022e | DUP11 | |
| 022f | DUP2 | |
| 0230 | MSTORE | |
| 0231 | PUSH2 | 0x023b |
| 0234 | PUSH1 | 0xa0 |
| 0236 | DUP3 | |
| 0237 | PUSH2 | 0x1620 |
| 023a | JUMP | |
| 023b | JUMPDEST | |
| 023c | MLOAD | |
| 023d | SWAP1 | |
| 023e | KECCAK256 | |
| 023f | PUSH2 | 0x0160 |
| 0242 | MLOAD | |
| 0243 | POP | |
| 0244 | PUSH1 | 0x40 |
| 0246 | MLOAD | |
| 0247 | DUP16 | |
| 0248 | DUP2 | |
| 0249 | ADD | |
| 024a | SWAP2 | |
| 024b | PUSH32 | 0xd850f5df47b124511e8e6ec99cf1a0beaf7c6237eff0a31305ce53d85f312675 |
| 026c | DUP4 | |
| 026d | MSTORE | |
| 026e | CHAINID | |
| 026f | PUSH1 | 0x40 |
| 0271 | DUP4 | |
| 0272 | ADD | |
| 0273 | MSTORE | |
| 0274 | ADDRESS | |
| 0275 | PUSH1 | 0x60 |
| 0277 | DUP4 | |
| 0278 | ADD | |
| 0279 | MSTORE | |
| 027a | PUSH32 | 0x5315ade0aa736cdc5532fa19a1ed12e3ce89b6ad07040b14bac780938e50423b |
| 029b | DUP13 | |
| 029c | DUP4 | |
| 029d | ADD | |
| 029e | MSTORE | |
| 029f | PUSH1 | 0x01 |
| 02a1 | PUSH1 | 0x01 |
| 02a3 | PUSH1 | 0x40 |
| 02a5 | SHL | |
| 02a6 | SUB | |
| 02a7 | DUP8 | |
| 02a8 | AND | |
| 02a9 | PUSH1 | 0xa0 |
| 02ab | DUP4 | |
| 02ac | ADD | |
| 02ad | MSTORE | |
| 02ae | PUSH1 | 0xc0 |
| 02b0 | DUP3 | |
| 02b1 | ADD | |
| 02b2 | MSTORE | |
| 02b3 | PUSH1 | 0xc0 |
| 02b5 | DUP2 | |
| 02b6 | MSTORE | |
| 02b7 | PUSH2 | 0x02c1 |
| 02ba | PUSH1 | 0xe0 |
| 02bc | DUP3 | |
| 02bd | PUSH2 | 0x1620 |
| 02c0 | JUMP | |
| 02c1 | JUMPDEST | |
| 02c2 | MLOAD | |
| 02c3 | SWAP1 | |
| 02c4 | KECCAK256 | |
| 02c5 | SWAP1 | |
| 02c6 | PUSH1 | 0x01 |
| 02c8 | SLOAD | |
| 02c9 | SWAP3 | |
| 02ca | PUSH32 | 0x000000000000000000000000a2e71fc2fb02d1ce93aa958e56cab83d26f3bfa6 |
| 02eb | PUSH2 | 0x1788 |
| 02ee | JUMP | |
| 02ef | JUMPDEST | |
| 02f0 | POP | |
| 02f1 | PUSH1 | 0x01 |
| 02f3 | PUSH1 | 0x01 |
| 02f5 | PUSH1 | 0x40 |
| 02f7 | SHL | |
| 02f8 | SUB | |
| 02f9 | PUSH2 | 0x0301 |
| 02fc | DUP10 | |
| 02fd | PUSH2 | 0x1655 |
| 0300 | JUMP | |
| 0301 | JUMPDEST | |
| 0302 | AND | |
| 0303 | SWAP1 | |
| 0304 | PUSH1 | 0x01 |
| 0306 | PUSH1 | 0x01 |
| 0308 | PUSH1 | 0x40 |
| 030a | SHL | |
| 030b | SUB | |
| 030c | NOT | |
| 030d | AND | |
| 030e | OR | |
| 030f | PUSH1 | 0x06 |
| 0311 | SSTORE | |
| 0312 | DUP6 | |
| 0313 | PUSH2 | 0x0160 |
| 0316 | MLOAD | |
| 0317 | MSTORE | |
| 0318 | PUSH1 | 0x04 |
| 031a | DUP9 | |
| 031b | MSTORE | |
| 031c | PUSH1 | 0x40 |
| 031e | PUSH2 | 0x0160 |
| 0321 | MLOAD | |
| 0322 | KECCAK256 | |
| 0323 | SWAP1 | |
| 0324 | DUP3 | |
| 0325 | DUP2 | |
| 0326 | SLOAD | |
| 0327 | SUB | |
| 0328 | DUP2 | |
| 0329 | SSTORE | |
| 032a | DUP3 | |
| 032b | DUP3 | |
| 032c | SLOAD | |
| 032d | ADD | |
| 032e | DUP3 | |
| 032f | SSTORE | |
| 0330 | PUSH1 | 0x01 |
| 0332 | DUP2 | |
| 0333 | ADD | |
| 0334 | PUSH1 | 0x01 |
| 0336 | PUSH1 | 0x01 |
| 0338 | PUSH1 | 0x40 |
| 033a | SHL | |
| 033b | SUB | |
| 033c | PUSH2 | 0x0347 |
| 033f | DUP2 | |
| 0340 | DUP4 | |
| 0341 | SLOAD | |
| 0342 | AND | |
| 0343 | PUSH2 | 0x1655 |
| 0346 | JUMP | |
| 0347 | JUMPDEST | |
| 0348 | AND | |
| 0349 | PUSH1 | 0x01 |
| 034b | PUSH1 | 0x01 |
| 034d | PUSH1 | 0x40 |
| 034f | SHL | |
| 0350 | SUB | |
| 0351 | NOT | |
| 0352 | DUP3 | |
| 0353 | SLOAD | |
| 0354 | AND | |
| 0355 | OR | |
| 0356 | SWAP1 | |
| 0357 | SSTORE | |
| 0358 | PUSH1 | 0x01 |
| 035a | DUP3 | |
| 035b | ADD | |
| 035c | PUSH1 | 0x01 |
| 035e | PUSH1 | 0x01 |
| 0360 | PUSH1 | 0x40 |
| 0362 | SHL | |
| 0363 | SUB | |
| 0364 | PUSH2 | 0x036f |
| 0367 | DUP2 | |
| 0368 | DUP4 | |
| 0369 | SLOAD | |
| 036a | AND | |
| 036b | PUSH2 | 0x1655 |
| 036e | JUMP | |
| 036f | JUMPDEST | |
| 0370 | AND | |
| 0371 | PUSH1 | 0x01 |
| 0373 | PUSH1 | 0x01 |
| 0375 | PUSH1 | 0x40 |
| 0377 | SHL | |
| 0378 | SUB | |
| 0379 | NOT | |
| 037a | DUP3 | |
| 037b | SLOAD | |
| 037c | AND | |
| 037d | OR | |
| 037e | SWAP1 | |
| 037f | SSTORE | |
| 0380 | PUSH2 | 0x0387 |
| 0383 | PUSH2 | 0x19fa |
| 0386 | JUMP | |
| 0387 | JUMPDEST | |
| 0388 | SLOAD | |
| 0389 | SWAP1 | |
| 038a | SLOAD | |
| 038b | SWAP1 | |
| 038c | PUSH1 | 0x40 |
| 038e | MLOAD | |
| 038f | SWAP3 | |
| 0390 | DUP4 | |
| 0391 | MSTORE | |
| 0392 | DUP9 | |
| 0393 | DUP4 | |
| 0394 | ADD | |
| 0395 | MSTORE | |
| 0396 | PUSH1 | 0x40 |
| 0398 | DUP3 | |
| 0399 | ADD | |
| 039a | MSTORE | |
| 039b | DUP6 | |
| 039c | PUSH1 | 0x60 |
| 039e | DUP3 | |
| 039f | ADD | |
| 03a0 | MSTORE | |
| 03a1 | LOG3 | |
| 03a2 | PUSH1 | 0x40 |
| 03a4 | MLOAD | |
| 03a5 | SWAP1 | |
| 03a6 | DUP2 | |
| 03a7 | MSTORE | |
| 03a8 | RETURN | |
| 03a9 | JUMPDEST | |
| 03aa | DUP9 | |
| 03ab | DUP7 | |
| 03ac | PUSH4 | 0x7c06acb7 |
| 03b1 | PUSH1 | 0xe1 |
| 03b3 | SHL | |
| 03b4 | PUSH2 | 0x0160 |
| 03b7 | MLOAD | |
| 03b8 | MSTORE | |
| 03b9 | PUSH1 | 0x04 |
| 03bb | MSTORE | |
| 03bc | PUSH1 | 0x24 |
| 03be | MSTORE | |
| 03bf | PUSH1 | 0x44 |
| 03c1 | MSTORE | |
| 03c2 | PUSH1 | 0x64 |
| 03c4 | PUSH2 | 0x0160 |
| 03c7 | MLOAD | |
| 03c8 | REVERT | |
| 03c9 | JUMPDEST | |
| 03ca | POP | |
| 03cb | POP | |
| 03cc | POP | |
| 03cd | PUSH4 | 0x108b1617 |
| 03d2 | PUSH1 | 0xe0 |
| 03d4 | SHL | |
| 03d5 | PUSH2 | 0x0160 |
| 03d8 | MLOAD | |
| 03d9 | MSTORE | |
| 03da | PUSH1 | 0x04 |
| 03dc | MSTORE | |
| 03dd | PUSH1 | 0x24 |
| 03df | MSTORE | |
| 03e0 | PUSH1 | 0x44 |
| 03e2 | PUSH2 | 0x0160 |
| 03e5 | MLOAD | |
| 03e6 | REVERT | |
| 03e7 | JUMPDEST | |
| 03e8 | POP | |
| 03e9 | DUP5 | |
| 03ea | DUP5 | |
| 03eb | EQ | |
| 03ec | PUSH2 | 0x01b5 |
| 03ef | JUMP | |
| 03f0 | JUMPDEST | |
| 03f1 | POP | |
| 03f2 | DUP5 | |
| 03f3 | ISZERO | |
| 03f4 | PUSH2 | 0x01ae |
| 03f7 | JUMP | |
| 03f8 | JUMPDEST | |
| 03f9 | PUSH4 | 0x1f2a2005 |
| 03fe | PUSH1 | 0xe0 |
| 0400 | SHL | |
| 0401 | PUSH2 | 0x0160 |
| 0404 | MLOAD | |
| 0405 | MSTORE | |
| 0406 | PUSH1 | 0x04 |
| 0408 | PUSH2 | 0x0160 |
| 040b | MLOAD | |
| 040c | REVERT | |
| 040d | JUMPDEST | |
| 040e | PUSH4 | 0xd311bc39 |
| 0413 | PUSH1 | 0xe0 |
| 0415 | SHL | |
| 0416 | PUSH2 | 0x0160 |
| 0419 | MLOAD | |
| 041a | MSTORE | |
| 041b | PUSH1 | 0x04 |
| 041d | PUSH2 | 0x0160 |
| 0420 | MLOAD | |
| 0421 | REVERT | |
| 0422 | JUMPDEST | |
| 0423 | CALLVALUE | |
| 0424 | PUSH2 | 0x012a |
| 0427 | JUMPI | |
| 0428 | PUSH1 | 0x20 |
| 042a | CALLDATASIZE | |
| 042b | PUSH1 | 0x03 |
| 042d | NOT | |
| 042e | ADD | |
| 042f | SLT | |
| 0430 | PUSH2 | 0x012a |
| 0433 | JUMPI | |
| 0434 | PUSH1 | 0x04 |
| 0436 | CALLDATALOAD | |
| 0437 | PUSH2 | 0x0160 |
| 043a | MLOAD | |
| 043b | MSTORE | |
| 043c | PUSH1 | 0x04 |
| 043e | PUSH1 | 0x20 |
| 0440 | MSTORE | |
| 0441 | PUSH1 | 0x20 |
| 0443 | PUSH1 | 0x40 |
| 0445 | PUSH2 | 0x0160 |
| 0448 | MLOAD | |
| 0449 | KECCAK256 | |
| 044a | SLOAD | |
| 044b | PUSH1 | 0x40 |
| 044d | MLOAD | |
| 044e | SWAP1 | |
| 044f | DUP2 | |
| 0450 | MSTORE | |
| 0451 | RETURN | |
| 0452 | JUMPDEST | |
| 0453 | CALLVALUE | |
| 0454 | PUSH2 | 0x012a |
| 0457 | JUMPI | |
| 0458 | PUSH2 | 0x0160 |
| 045b | MLOAD | |
| 045c | CALLDATASIZE | |
| 045d | PUSH1 | 0x03 |
| 045f | NOT | |
| 0460 | ADD | |
| 0461 | SLT | |
| 0462 | PUSH2 | 0x012a |
| 0465 | JUMPI | |
| 0466 | PUSH1 | 0x20 |
| 0468 | PUSH1 | 0x40 |
| 046a | MLOAD | |
| 046b | PUSH32 | 0xbc5858e168b959a61a8fb2d7957ef31dbed683a362770ca030e5d772cc44e068 |
| 048c | DUP2 | |
| 048d | MSTORE | |
| 048e | RETURN | |
| 048f | JUMPDEST | |
| 0490 | CALLVALUE | |
| 0491 | PUSH2 | 0x012a |
| 0494 | JUMPI | |
| 0495 | PUSH2 | 0x0160 |
| 0498 | MLOAD | |
| 0499 | CALLDATASIZE | |
| 049a | PUSH1 | 0x03 |
| 049c | NOT | |
| 049d | ADD | |
| 049e | SLT | |
| 049f | PUSH2 | 0x012a |
| 04a2 | JUMPI | |
| 04a3 | PUSH1 | 0x20 |
| 04a5 | PUSH1 | 0x01 |
| 04a7 | PUSH1 | 0x01 |
| 04a9 | PUSH1 | 0x40 |
| 04ab | SHL | |
| 04ac | SUB | |
| 04ad | PUSH1 | 0x06 |
| 04af | SLOAD | |
| 04b0 | AND | |
| 04b1 | PUSH1 | 0x40 |
| 04b3 | MLOAD | |
| 04b4 | SWAP1 | |
| 04b5 | DUP2 | |
| 04b6 | MSTORE | |
| 04b7 | RETURN | |
| 04b8 | JUMPDEST | |
| 04b9 | CALLVALUE | |
| 04ba | PUSH2 | 0x012a |
| 04bd | JUMPI | |
| 04be | PUSH1 | 0x80 |
| 04c0 | CALLDATASIZE | |
| 04c1 | PUSH1 | 0x03 |
| 04c3 | NOT | |
| 04c4 | ADD | |
| 04c5 | SLT | |
| 04c6 | PUSH2 | 0x012a |
| 04c9 | JUMPI | |
| 04ca | PUSH1 | 0x04 |
| 04cc | CALLDATALOAD | |
| 04cd | PUSH1 | 0x24 |
| 04cf | CALLDATALOAD | |
| 04d0 | PUSH2 | 0x04d7 |
| 04d3 | PUSH2 | 0x15da |
| 04d6 | JUMP | |
| 04d7 | JUMPDEST | |
| 04d8 | SWAP2 | |
| 04d9 | PUSH1 | 0x64 |
| 04db | CALLDATALOAD | |
| 04dc | PUSH1 | 0x01 |
| 04de | PUSH1 | 0x01 |
| 04e0 | PUSH1 | 0x40 |
| 04e2 | SHL | |
| 04e3 | SUB | |
| 04e4 | DUP2 | |
| 04e5 | GT | |
| 04e6 | PUSH2 | 0x012a |
| 04e9 | JUMPI | |
| 04ea | PUSH2 | 0x04f7 |
| 04ed | SWAP1 | |
| 04ee | CALLDATASIZE | |
| 04ef | SWAP1 | |
| 04f0 | PUSH1 | 0x04 |
| 04f2 | ADD | |
| 04f3 | PUSH2 | 0x15f0 |
| 04f6 | JUMP | |
| 04f7 | JUMPDEST | |
| 04f8 | SWAP3 | |
| 04f9 | SWAP1 | |
| 04fa | PUSH1 | 0x02 |
| 04fc | SLOAD | |
| 04fd | SWAP5 | |
| 04fe | DUP6 | |
| 04ff | ISZERO | |
| 0500 | PUSH2 | 0x040d |
| 0503 | JUMPI | |
| 0504 | DUP3 | |
| 0505 | ISZERO | |
| 0506 | PUSH2 | 0x03f8 |
| 0509 | JUMPI | |
| 050a | PUSH1 | 0x03 |
| 050c | SLOAD | |
| 050d | SWAP6 | |
| 050e | DUP7 | |
| 050f | DUP5 | |
| 0510 | GT | |
| 0511 | PUSH2 | 0x068f |
| 0514 | JUMPI | |
| 0515 | SWAP6 | |
| 0516 | PUSH1 | 0x80 |
| 0518 | SWAP3 | |
| 0519 | PUSH2 | 0x05fa |
| 051c | PUSH32 | 0x4565741fc5c16ad3a3a3fbbf4311621df9850edf4097f549079a6855d2133135 |
| 053d | SWAP6 | |
| 053e | SWAP4 | |
| 053f | PUSH1 | 0x20 |
| 0541 | SWAP10 | |
| 0542 | PUSH1 | 0x06 |
| 0544 | SLOAD | |
| 0545 | SWAP4 | |
| 0546 | PUSH1 | 0x01 |
| 0548 | PUSH1 | 0x01 |
| 054a | PUSH1 | 0x40 |
| 054c | SHL | |
| 054d | SUB | |
| 054e | DUP6 | |
| 054f | AND | |
| 0550 | SWAP11 | |
| 0551 | PUSH1 | 0x40 |
| 0553 | MLOAD | |
| 0554 | DUP14 | |
| 0555 | DUP2 | |
| 0556 | ADD | |
| 0557 | SWAP1 | |
| 0558 | DUP14 | |
| 0559 | DUP3 | |
| 055a | MSTORE | |
| 055b | DUP13 | |
| 055c | PUSH1 | 0x40 |
| 055e | DUP3 | |
| 055f | ADD | |
| 0560 | MSTORE | |
| 0561 | DUP10 | |
| 0562 | PUSH1 | 0x60 |
| 0564 | DUP3 | |
| 0565 | ADD | |
| 0566 | MSTORE | |
| 0567 | PUSH1 | 0x60 |
| 0569 | DUP2 | |
| 056a | MSTORE | |
| 056b | PUSH2 | 0x0574 |
| 056e | DUP12 | |
| 056f | DUP3 | |
| 0570 | PUSH2 | 0x1620 |
| 0573 | JUMP | |
| 0574 | JUMPDEST | |
| 0575 | MLOAD | |
| 0576 | SWAP1 | |
| 0577 | KECCAK256 | |
| 0578 | PUSH2 | 0x0160 |
| 057b | MLOAD | |
| 057c | POP | |
| 057d | PUSH1 | 0x40 |
| 057f | MLOAD | |
| 0580 | DUP15 | |
| 0581 | DUP2 | |
| 0582 | ADD | |
| 0583 | SWAP2 | |
| 0584 | PUSH32 | 0xd850f5df47b124511e8e6ec99cf1a0beaf7c6237eff0a31305ce53d85f312675 |
| 05a5 | DUP4 | |
| 05a6 | MSTORE | |
| 05a7 | CHAINID | |
| 05a8 | PUSH1 | 0x40 |
| 05aa | DUP4 | |
| 05ab | ADD | |
| 05ac | MSTORE | |
| 05ad | ADDRESS | |
| 05ae | PUSH1 | 0x60 |
| 05b0 | DUP4 | |
| 05b1 | ADD | |
| 05b2 | MSTORE | |
| 05b3 | PUSH32 | 0xef06d5e846d5c9e7b4cf0eb3e3b66d716af68a3cea05cd7bc7743bbc17740522 |
| 05d4 | DUP13 | |
| 05d5 | DUP4 | |
| 05d6 | ADD | |
| 05d7 | MSTORE | |
| 05d8 | PUSH1 | 0x01 |
| 05da | PUSH1 | 0x01 |
| 05dc | PUSH1 | 0x40 |
| 05de | SHL | |
| 05df | SUB | |
| 05e0 | DUP8 | |
| 05e1 | AND | |
| 05e2 | PUSH1 | 0xa0 |
| 05e4 | DUP4 | |
| 05e5 | ADD | |
| 05e6 | MSTORE | |
| 05e7 | PUSH1 | 0xc0 |
| 05e9 | DUP3 | |
| 05ea | ADD | |
| 05eb | MSTORE | |
| 05ec | PUSH1 | 0xc0 |
| 05ee | DUP2 | |
| 05ef | MSTORE | |
| 05f0 | PUSH2 | 0x02c1 |
| 05f3 | PUSH1 | 0xe0 |
| 05f5 | DUP3 | |
| 05f6 | PUSH2 | 0x1620 |
| 05f9 | JUMP | |
| 05fa | JUMPDEST | |
| 05fb | POP | |
| 05fc | PUSH1 | 0x01 |
| 05fe | PUSH1 | 0x01 |
| 0600 | PUSH1 | 0x40 |
| 0602 | SHL | |
| 0603 | SUB | |
| 0604 | PUSH2 | 0x060c |
| 0607 | DUP9 | |
| 0608 | PUSH2 | 0x1655 |
| 060b | JUMP | |
| 060c | JUMPDEST | |
| 060d | AND | |
| 060e | SWAP1 | |
| 060f | PUSH1 | 0x01 |
| 0611 | PUSH1 | 0x01 |
| 0613 | PUSH1 | 0x40 |
| 0615 | SHL | |
| 0616 | SUB | |
| 0617 | NOT | |
| 0618 | AND | |
| 0619 | OR | |
| 061a | PUSH1 | 0x06 |
| 061c | SSTORE | |
| 061d | DUP5 | |
| 061e | PUSH2 | 0x0160 |
| 0621 | MLOAD | |
| 0622 | MSTORE | |
| 0623 | PUSH1 | 0x04 |
| 0625 | DUP8 | |
| 0626 | MSTORE | |
| 0627 | DUP2 | |
| 0628 | PUSH1 | 0x40 |
| 062a | PUSH2 | 0x0160 |
| 062d | MLOAD | |
| 062e | KECCAK256 | |
| 062f | SWAP2 | |
| 0630 | SUB | |
| 0631 | PUSH1 | 0x03 |
| 0633 | SSTORE | |
| 0634 | DUP2 | |
| 0635 | DUP2 | |
| 0636 | SLOAD | |
| 0637 | ADD | |
| 0638 | DUP2 | |
| 0639 | SSTORE | |
| 063a | DUP2 | |
| 063b | PUSH1 | 0x05 |
| 063d | SLOAD | |
| 063e | ADD | |
| 063f | PUSH1 | 0x05 |
| 0641 | SSTORE | |
| 0642 | PUSH1 | 0x01 |
| 0644 | PUSH1 | 0x01 |
| 0646 | PUSH1 | 0x40 |
| 0648 | SHL | |
| 0649 | SUB | |
| 064a | PUSH1 | 0x01 |
| 064c | DUP3 | |
| 064d | ADD | |
| 064e | SWAP2 | |
| 064f | DUP2 | |
| 0650 | PUSH2 | 0x065b |
| 0653 | DUP2 | |
| 0654 | DUP6 | |
| 0655 | SLOAD | |
| 0656 | AND | |
| 0657 | PUSH2 | 0x1655 |
| 065a | JUMP | |
| 065b | JUMPDEST | |
| 065c | AND | |
| 065d | DUP3 | |
| 065e | NOT | |
| 065f | DUP5 | |
| 0660 | SLOAD | |
| 0661 | AND | |
| 0662 | OR | |
| 0663 | DUP4 | |
| 0664 | SSTORE | |
| 0665 | PUSH2 | 0x066c |
| 0668 | PUSH2 | 0x19fa |
| 066b | JUMP | |
| 066c | JUMPDEST | |
| 066d | SLOAD | |
| 066e | SWAP2 | |
| 066f | SLOAD | |
| 0670 | AND | |
| 0671 | SWAP1 | |
| 0672 | PUSH1 | 0x40 |
| 0674 | MLOAD | |
| 0675 | SWAP3 | |
| 0676 | DUP4 | |
| 0677 | MSTORE | |
| 0678 | DUP8 | |
| 0679 | DUP4 | |
| 067a | ADD | |
| 067b | MSTORE | |
| 067c | PUSH1 | 0x40 |
| 067e | DUP3 | |
| 067f | ADD | |
| 0680 | MSTORE | |
| 0681 | DUP5 | |
| 0682 | PUSH1 | 0x60 |
| 0684 | DUP3 | |
| 0685 | ADD | |
| 0686 | MSTORE | |
| 0687 | LOG2 | |
| 0688 | PUSH1 | 0x40 |
| 068a | MLOAD | |
| 068b | SWAP1 | |
| 068c | DUP2 | |
| 068d | MSTORE | |
| 068e | RETURN | |
| 068f | JUMPDEST | |
| 0690 | DUP7 | |
| 0691 | DUP5 | |
| 0692 | PUSH4 | 0x11250051 |
| 0697 | PUSH1 | 0xe2 |
| 0699 | SHL | |
| 069a | PUSH2 | 0x0160 |
| 069d | MLOAD | |
| 069e | MSTORE | |
| 069f | PUSH1 | 0x04 |
| 06a1 | MSTORE | |
| 06a2 | PUSH1 | 0x24 |
| 06a4 | MSTORE | |
| 06a5 | PUSH1 | 0x44 |
| 06a7 | PUSH2 | 0x0160 |
| 06aa | MLOAD | |
| 06ab | REVERT | |
| 06ac | JUMPDEST | |
| 06ad | CALLVALUE | |
| 06ae | PUSH2 | 0x012a |
| 06b1 | JUMPI | |
| 06b2 | PUSH2 | 0x0160 |
| 06b5 | MLOAD | |
| 06b6 | CALLDATASIZE | |
| 06b7 | PUSH1 | 0x03 |
| 06b9 | NOT | |
| 06ba | ADD | |
| 06bb | SLT | |
| 06bc | PUSH2 | 0x012a |
| 06bf | JUMPI | |
| 06c0 | PUSH1 | 0x20 |
| 06c2 | PUSH1 | 0x03 |
| 06c4 | SLOAD | |
| 06c5 | PUSH1 | 0x40 |
| 06c7 | MLOAD | |
| 06c8 | SWAP1 | |
| 06c9 | DUP2 | |
| 06ca | MSTORE | |
| 06cb | RETURN | |
| 06cc | JUMPDEST | |
| 06cd | CALLVALUE | |
| 06ce | PUSH2 | 0x012a |
| 06d1 | JUMPI | |
| 06d2 | PUSH2 | 0x0100 |
| 06d5 | CALLDATASIZE | |
| 06d6 | PUSH1 | 0x03 |
| 06d8 | NOT | |
| 06d9 | ADD | |
| 06da | SLT | |
| 06db | PUSH2 | 0x012a |
| 06de | JUMPI | |
| 06df | PUSH1 | 0x04 |
| 06e1 | CALLDATALOAD | |
| 06e2 | PUSH1 | 0x01 |
| 06e4 | PUSH1 | 0x01 |
| 06e6 | PUSH1 | 0x40 |
| 06e8 | SHL | |
| 06e9 | SUB | |
| 06ea | DUP2 | |
| 06eb | GT | |
| 06ec | PUSH2 | 0x012a |
| 06ef | JUMPI | |
| 06f0 | PUSH2 | 0x06fd |
| 06f3 | SWAP1 | |
| 06f4 | CALLDATASIZE | |
| 06f5 | SWAP1 | |
| 06f6 | PUSH1 | 0x04 |
| 06f8 | ADD | |
| 06f9 | PUSH2 | 0x15f0 |
| 06fc | JUMP | |
| 06fd | JUMPDEST | |
| 06fe | PUSH2 | 0x0180 |
| 0701 | MSTORE | |
| 0702 | PUSH1 | 0x24 |
| 0704 | CALLDATALOAD | |
| 0705 | PUSH1 | 0x01 |
| 0707 | PUSH1 | 0x01 |
| 0709 | PUSH1 | 0x40 |
| 070b | SHL | |
| 070c | SUB | |
| 070d | DUP2 | |
| 070e | GT | |
| 070f | PUSH2 | 0x012a |
| 0712 | JUMPI | |
| 0713 | PUSH2 | 0x0720 |
| 0716 | SWAP1 | |
| 0717 | CALLDATASIZE | |
| 0718 | SWAP1 | |
| 0719 | PUSH1 | 0x04 |
| 071b | ADD | |
| 071c | PUSH2 | 0x15f0 |
| 071f | JUMP | |
| 0720 | JUMPDEST | |
| 0721 | PUSH1 | 0x44 |
| 0723 | SWAP3 | |
| 0724 | SWAP2 | |
| 0725 | SWAP3 | |
| 0726 | CALLDATALOAD | |
| 0727 | PUSH1 | 0x01 |
| 0729 | PUSH1 | 0x01 |
| 072b | PUSH1 | 0x40 |
| 072d | SHL | |
| 072e | SUB | |
| 072f | DUP2 | |
| 0730 | GT | |
| 0731 | PUSH2 | 0x012a |
| 0734 | JUMPI | |
| 0735 | PUSH2 | 0x0742 |
| 0738 | SWAP1 | |
| 0739 | CALLDATASIZE | |
| 073a | SWAP1 | |
| 073b | PUSH1 | 0x04 |
| 073d | ADD | |
| 073e | PUSH2 | 0x15f0 |
| 0741 | JUMP | |
| 0742 | JUMPDEST | |
| 0743 | PUSH1 | 0xa0 |
| 0745 | MSTORE | |
| 0746 | PUSH1 | 0x80 |
| 0748 | MSTORE | |
| 0749 | PUSH1 | 0x64 |
| 074b | CALLDATALOAD | |
| 074c | PUSH1 | 0x01 |
| 074e | PUSH1 | 0x01 |
| 0750 | PUSH1 | 0x40 |
| 0752 | SHL | |
| 0753 | SUB | |
| 0754 | DUP2 | |
| 0755 | GT | |
| 0756 | PUSH2 | 0x012a |
| 0759 | JUMPI | |
| 075a | PUSH2 | 0x0767 |
| 075d | SWAP1 | |
| 075e | CALLDATASIZE | |
| 075f | SWAP1 | |
| 0760 | PUSH1 | 0x04 |
| 0762 | ADD | |
| 0763 | PUSH2 | 0x15f0 |
| 0766 | JUMP | |
| 0767 | JUMPDEST | |
| 0768 | PUSH2 | 0x0120 |
| 076b | MSTORE | |
| 076c | PUSH2 | 0x0100 |
| 076f | MSTORE | |
| 0770 | PUSH1 | 0x84 |
| 0772 | CALLDATALOAD | |
| 0773 | PUSH1 | 0x01 |
| 0775 | PUSH1 | 0x01 |
| 0777 | PUSH1 | 0x40 |
| 0779 | SHL | |
| 077a | SUB | |
| 077b | DUP2 | |
| 077c | GT | |
| 077d | PUSH2 | 0x012a |
| 0780 | JUMPI | |
| 0781 | PUSH2 | 0x078e |
| 0784 | SWAP1 | |
| 0785 | CALLDATASIZE | |
| 0786 | SWAP1 | |
| 0787 | PUSH1 | 0x04 |
| 0789 | ADD | |
| 078a | PUSH2 | 0x15f0 |
| 078d | JUMP | |
| 078e | JUMPDEST | |
| 078f | PUSH1 | 0xc0 |
| 0791 | MSTORE | |
| 0792 | PUSH1 | 0xe0 |
| 0794 | MSTORE | |
| 0795 | PUSH1 | 0xa4 |
| 0797 | CALLDATALOAD | |
| 0798 | PUSH2 | 0x0140 |
| 079b | DUP2 | |
| 079c | SWAP1 | |
| 079d | MSTORE | |
| 079e | PUSH1 | 0x01 |
| 07a0 | PUSH1 | 0x01 |
| 07a2 | PUSH1 | 0x40 |
| 07a4 | SHL | |
| 07a5 | SUB | |
| 07a6 | DUP2 | |
| 07a7 | AND | |
| 07a8 | SWAP1 | |
| 07a9 | SUB | |
| 07aa | PUSH2 | 0x012a |
| 07ad | JUMPI | |
| 07ae | PUSH1 | 0xc4 |
| 07b0 | CALLDATALOAD | |
| 07b1 | PUSH1 | 0x01 |
| 07b3 | PUSH1 | 0x01 |
| 07b5 | PUSH1 | 0x40 |
| 07b7 | SHL | |
| 07b8 | SUB | |
| 07b9 | DUP2 | |
| 07ba | AND | |
| 07bb | DUP2 | |
| 07bc | SUB | |
| 07bd | PUSH2 | 0x012a |
| 07c0 | JUMPI | |
| 07c1 | PUSH1 | 0xe4 |
| 07c3 | CALLDATALOAD | |
| 07c4 | PUSH1 | 0x01 |
| 07c6 | PUSH1 | 0x01 |
| 07c8 | PUSH1 | 0x40 |
| 07ca | SHL | |
| 07cb | SUB | |
| 07cc | DUP2 | |
| 07cd | GT | |
| 07ce | PUSH2 | 0x012a |
| 07d1 | JUMPI | |
| 07d2 | PUSH2 | 0x07df |
| 07d5 | SWAP1 | |
| 07d6 | CALLDATASIZE | |
| 07d7 | SWAP1 | |
| 07d8 | PUSH1 | 0x04 |
| 07da | ADD | |
| 07db | PUSH2 | 0x15f0 |
| 07de | JUMP | |
| 07df | JUMPDEST | |
| 07e0 | PUSH1 | 0x40 |
| 07e2 | MLOAD | |
| 07e3 | PUSH4 | 0x28305db1 |
| 07e8 | PUSH1 | 0xe2 |
| 07ea | SHL | |
| 07eb | DUP2 | |
| 07ec | MSTORE | |
| 07ed | SWAP1 | |
| 07ee | SWAP2 | |
| 07ef | SWAP1 | |
| 07f0 | PUSH1 | 0x20 |
| 07f2 | DUP2 | |
| 07f3 | PUSH1 | 0x04 |
| 07f5 | DUP2 | |
| 07f6 | PUSH32 | 0x000000000000000000000000a2e71fc2fb02d1ce93aa958e56cab83d26f3bfa6 |
| 0817 | PUSH1 | 0x01 |
| 0819 | PUSH1 | 0x01 |
| 081b | PUSH1 | 0xa0 |
| 081d | SHL | |
| 081e | SUB | |
| 081f | AND | |
| 0820 | GAS | |
| 0821 | STATICCALL | |
| 0822 | SWAP1 | |
| 0823 | DUP2 | |
| 0824 | ISZERO | |
| 0825 | PUSH2 | 0x0cf3 |
| 0828 | JUMPI | |
| 0829 | PUSH2 | 0x0160 |
| 082c | MLOAD | |
| 082d | SWAP2 | |
| 082e | PUSH2 | 0x0e7c |
| 0831 | JUMPI | |
| 0832 | JUMPDEST | |
| 0833 | POP | |
| 0834 | DUP1 | |
| 0835 | ISZERO | |
| 0836 | PUSH2 | 0x0dd7 |
| 0839 | JUMPI | |
| 083a | JUMPDEST | |
| 083b | PUSH2 | 0x0b22 |
| 083e | JUMPI | |
| 083f | JUMPDEST | |
| 0840 | POP | |
| 0841 | POP | |
| 0842 | POP | |
| 0843 | PUSH1 | 0x01 |
| 0845 | PUSH1 | 0x01 |
| 0847 | PUSH1 | 0x40 |
| 0849 | SHL | |
| 084a | SUB | |
| 084b | PUSH1 | 0x06 |
| 084d | SLOAD | |
| 084e | AND | |
| 084f | ISZERO | |
| 0850 | DUP1 | |
| 0851 | ISZERO | |
| 0852 | SWAP1 | |
| 0853 | PUSH2 | 0x0b17 |
| 0856 | JUMPI | |
| 0857 | JUMPDEST | |
| 0858 | PUSH2 | 0x0b02 |
| 085b | JUMPI | |
| 085c | DUP1 | |
| 085d | PUSH2 | 0x0180 |
| 0860 | MLOAD | |
| 0861 | EQ | |
| 0862 | DUP1 | |
| 0863 | ISZERO | |
| 0864 | SWAP1 | |
| 0865 | PUSH2 | 0x0af3 |
| 0868 | JUMPI | |
| 0869 | JUMPDEST | |
| 086a | PUSH2 | 0x0abc |
| 086d | JUMPI | |
| 086e | PUSH1 | 0xc0 |
| 0870 | MLOAD | |
| 0871 | PUSH2 | 0x0120 |
| 0874 | MLOAD | |
| 0875 | SUB | |
| 0876 | PUSH2 | 0x0abc |
| 0879 | JUMPI | |
| 087a | PUSH2 | 0x0160 |
| 087d | MLOAD | |
| 087e | SWAP3 | |
| 087f | DUP4 | |
| 0880 | SWAP3 | |
| 0881 | SWAP2 | |
| 0882 | SWAP1 | |
| 0883 | JUMPDEST | |
| 0884 | PUSH2 | 0x0180 |
| 0887 | MLOAD | |
| 0888 | DUP5 | |
| 0889 | LT | |
| 088a | PUSH2 | 0x09e0 |
| 088d | JUMPI | |
| 088e | DUP5 | |
| 088f | PUSH11 | 0x52b7d2dcc80cd2e4000000 |
| 089b | DUP2 | |
| 089c | GT | |
| 089d | PUSH2 | 0x09b9 |
| 08a0 | JUMPI | |
| 08a1 | DUP1 | |
| 08a2 | PUSH1 | 0x05 |
| 08a4 | SSTORE | |
| 08a5 | PUSH11 | 0x52b7d2dcc80cd2e4000000 |
| 08b1 | SUB | |
| 08b2 | PUSH11 | 0x52b7d2dcc80cd2e4000000 |
| 08be | DUP2 | |
| 08bf | GT | |
| 08c0 | PUSH2 | 0x099f |
| 08c3 | JUMPI | |
| 08c4 | PUSH1 | 0x03 |
| 08c6 | SSTORE | |
| 08c7 | PUSH2 | 0x0160 |
| 08ca | MLOAD | |
| 08cb | JUMPDEST | |
| 08cc | PUSH2 | 0x0120 |
| 08cf | MLOAD | |
| 08d0 | DUP2 | |
| 08d1 | LT | |
| 08d2 | PUSH2 | 0x094a |
| 08d5 | JUMPI | |
| 08d6 | PUSH1 | 0x01 |
| 08d8 | PUSH1 | 0x01 |
| 08da | PUSH1 | 0x40 |
| 08dc | SHL | |
| 08dd | SUB | |
| 08de | PUSH2 | 0x0140 |
| 08e1 | MLOAD | |
| 08e2 | AND | |
| 08e3 | PUSH1 | 0x01 |
| 08e5 | PUSH1 | 0x01 |
| 08e7 | PUSH1 | 0x40 |
| 08e9 | SHL | |
| 08ea | SUB | |
| 08eb | NOT | |
| 08ec | PUSH1 | 0x06 |
| 08ee | SLOAD | |
| 08ef | AND | |
| 08f0 | OR | |
| 08f1 | PUSH1 | 0x06 |
| 08f3 | SSTORE | |
| 08f4 | PUSH2 | 0x08fb |
| 08f7 | PUSH2 | 0x19fa |
| 08fa | JUMP | |
| 08fb | JUMPDEST | |
| 08fc | PUSH32 | 0xb04da588109787f2e1bce4cc15cc0e414cae26034cea4902695311f75568bf87 |
| 091d | PUSH1 | 0x60 |
| 091f | PUSH1 | 0x40 |
| 0921 | MLOAD | |
| 0922 | PUSH2 | 0x0180 |
| 0925 | MLOAD | |
| 0926 | DUP2 | |
| 0927 | MSTORE | |
| 0928 | PUSH2 | 0x0120 |
| 092b | MLOAD | |
| 092c | PUSH1 | 0x20 |
| 092e | DUP3 | |
| 092f | ADD | |
| 0930 | MSTORE | |
| 0931 | PUSH1 | 0x01 |
| 0933 | PUSH1 | 0x01 |
| 0935 | PUSH1 | 0x40 |
| 0937 | SHL | |
| 0938 | SUB | |
| 0939 | PUSH2 | 0x0140 |
| 093c | MLOAD | |
| 093d | AND | |
| 093e | PUSH1 | 0x40 |
| 0940 | DUP3 | |
| 0941 | ADD | |
| 0942 | MSTORE | |
| 0943 | LOG1 | |
| 0944 | PUSH2 | 0x0160 |
| 0947 | MLOAD | |
| 0948 | DUP1 | |
| 0949 | RETURN | |
| 094a | JUMPDEST | |
| 094b | DUP1 | |
| 094c | PUSH2 | 0x095e |
| 094f | PUSH1 | 0x01 |
| 0951 | SWAP3 | |
| 0952 | PUSH2 | 0x0120 |
| 0955 | MLOAD | |
| 0956 | PUSH2 | 0x0100 |
| 0959 | MLOAD | |
| 095a | PUSH2 | 0x1721 |
| 095d | JUMP | |
| 095e | JUMPDEST | |
| 095f | CALLDATALOAD | |
| 0960 | PUSH2 | 0x0160 |
| 0963 | MLOAD | |
| 0964 | MSTORE | |
| 0965 | PUSH1 | 0x07 |
| 0967 | PUSH1 | 0x20 |
| 0969 | MSTORE | |
| 096a | PUSH1 | 0x40 |
| 096c | PUSH2 | 0x0160 |
| 096f | MLOAD | |
| 0970 | KECCAK256 | |
| 0971 | PUSH2 | 0x097f |
| 0974 | DUP3 | |
| 0975 | PUSH1 | 0xc0 |
| 0977 | MLOAD | |
| 0978 | PUSH1 | 0xe0 |
| 097a | MLOAD | |
| 097b | PUSH2 | 0x1721 |
| 097e | JUMP | |
| 097f | JUMPDEST | |
| 0980 | CALLDATALOAD | |
| 0981 | PUSH2 | 0x0160 |
| 0984 | MLOAD | |
| 0985 | MSTORE | |
| 0986 | PUSH1 | 0x20 |
| 0988 | MSTORE | |
| 0989 | PUSH1 | 0x40 |
| 098b | PUSH2 | 0x0160 |
| 098e | MLOAD | |
| 098f | KECCAK256 | |
| 0990 | DUP3 | |
| 0991 | PUSH1 | 0xff |
| 0993 | NOT | |
| 0994 | DUP3 | |
| 0995 | SLOAD | |
| 0996 | AND | |
| 0997 | OR | |
| 0998 | SWAP1 | |
| 0999 | SSTORE | |
| 099a | ADD | |
| 099b | PUSH2 | 0x08cb |
| 099e | JUMP | |
| 099f | JUMPDEST | |
| 09a0 | PUSH4 | 0x4e487b71 |
| 09a5 | PUSH1 | 0xe0 |
| 09a7 | SHL | |
| 09a8 | PUSH2 | 0x0160 |
| 09ab | MLOAD | |
| 09ac | MSTORE | |
| 09ad | PUSH1 | 0x11 |
| 09af | PUSH1 | 0x04 |
| 09b1 | MSTORE | |
| 09b2 | PUSH1 | 0x24 |
| 09b4 | PUSH2 | 0x0160 |
| 09b7 | MLOAD | |
| 09b8 | REVERT | |
| 09b9 | JUMPDEST | |
| 09ba | PUSH4 | 0x11250051 |
| 09bf | PUSH1 | 0xe2 |
| 09c1 | SHL | |
| 09c2 | PUSH2 | 0x0160 |
| 09c5 | MLOAD | |
| 09c6 | MSTORE | |
| 09c7 | PUSH1 | 0x04 |
| 09c9 | MSTORE | |
| 09ca | PUSH11 | 0x52b7d2dcc80cd2e4000000 |
| 09d6 | PUSH1 | 0x24 |
| 09d8 | MSTORE | |
| 09d9 | PUSH1 | 0x44 |
| 09db | PUSH2 | 0x0160 |
| 09de | MLOAD | |
| 09df | REVERT | |
| 09e0 | JUMPDEST | |
| 09e1 | SWAP1 | |
| 09e2 | SWAP2 | |
| 09e3 | SWAP3 | |
| 09e4 | SWAP4 | |
| 09e5 | PUSH2 | 0x09f2 |
| 09e8 | DUP6 | |
| 09e9 | PUSH2 | 0x0180 |
| 09ec | MLOAD | |
| 09ed | DUP7 | |
| 09ee | PUSH2 | 0x1721 |
| 09f1 | JUMP | |
| 09f2 | JUMPDEST | |
| 09f3 | CALLDATALOAD | |
| 09f4 | ISZERO | |
| 09f5 | DUP1 | |
| 09f6 | ISZERO | |
| 09f7 | PUSH2 | 0x0ad1 |
| 09fa | JUMPI | |
| 09fb | JUMPDEST | |
| 09fc | PUSH2 | 0x0abc |
| 09ff | JUMPI | |
| 0a00 | PUSH2 | 0x0a0d |
| 0a03 | DUP6 | |
| 0a04 | PUSH2 | 0x0180 |
| 0a07 | MLOAD | |
| 0a08 | DUP7 | |
| 0a09 | PUSH2 | 0x1721 |
| 0a0c | JUMP | |
| 0a0d | JUMPDEST | |
| 0a0e | CALLDATALOAD | |
| 0a0f | PUSH2 | 0x0160 |
| 0a12 | MLOAD | |
| 0a13 | MSTORE | |
| 0a14 | PUSH1 | 0x04 |
| 0a16 | PUSH1 | 0x20 |
| 0a18 | MSTORE | |
| 0a19 | PUSH1 | 0x40 |
| 0a1b | PUSH2 | 0x0160 |
| 0a1e | MLOAD | |
| 0a1f | KECCAK256 | |
| 0a20 | PUSH1 | 0x01 |
| 0a22 | DUP2 | |
| 0a23 | ADD | |
| 0a24 | SWAP1 | |
| 0a25 | PUSH1 | 0x01 |
| 0a27 | PUSH1 | 0x01 |
| 0a29 | PUSH1 | 0x40 |
| 0a2b | SHL | |
| 0a2c | SUB | |
| 0a2d | DUP3 | |
| 0a2e | SLOAD | |
| 0a2f | AND | |
| 0a30 | PUSH2 | 0x0a94 |
| 0a33 | JUMPI | |
| 0a34 | SWAP2 | |
| 0a35 | PUSH2 | 0x0a8a |
| 0a38 | SWAP2 | |
| 0a39 | PUSH1 | 0x01 |
| 0a3b | SWAP4 | |
| 0a3c | PUSH2 | 0x0a46 |
| 0a3f | DUP10 | |
| 0a40 | DUP9 | |
| 0a41 | DUP9 | |
| 0a42 | PUSH2 | 0x1721 |
| 0a45 | JUMP | |
| 0a46 | JUMPDEST | |
| 0a47 | CALLDATALOAD | |
| 0a48 | SWAP1 | |
| 0a49 | SSTORE | |
| 0a4a | PUSH1 | 0x01 |
| 0a4c | PUSH1 | 0x01 |
| 0a4e | PUSH1 | 0x40 |
| 0a50 | SHL | |
| 0a51 | SUB | |
| 0a52 | PUSH2 | 0x0a68 |
| 0a55 | PUSH2 | 0x0a63 |
| 0a58 | DUP11 | |
| 0a59 | PUSH1 | 0xa0 |
| 0a5b | MLOAD | |
| 0a5c | PUSH1 | 0x80 |
| 0a5e | MLOAD | |
| 0a5f | PUSH2 | 0x1721 |
| 0a62 | JUMP | |
| 0a63 | JUMPDEST | |
| 0a64 | PUSH2 | 0x1745 |
| 0a67 | JUMP | |
| 0a68 | JUMPDEST | |
| 0a69 | AND | |
| 0a6a | PUSH1 | 0x01 |
| 0a6c | PUSH1 | 0x01 |
| 0a6e | PUSH1 | 0x40 |
| 0a70 | SHL | |
| 0a71 | SUB | |
| 0a72 | NOT | |
| 0a73 | DUP3 | |
| 0a74 | SLOAD | |
| 0a75 | AND | |
| 0a76 | OR | |
| 0a77 | SWAP1 | |
| 0a78 | SSTORE | |
| 0a79 | PUSH2 | 0x0a83 |
| 0a7c | DUP8 | |
| 0a7d | DUP7 | |
| 0a7e | DUP7 | |
| 0a7f | PUSH2 | 0x1721 |
| 0a82 | JUMP | |
| 0a83 | JUMPDEST | |
| 0a84 | CALLDATALOAD | |
| 0a85 | SWAP1 | |
| 0a86 | PUSH2 | 0x1687 |
| 0a89 | JUMP | |
| 0a8a | JUMPDEST | |
| 0a8b | SWAP5 | |
| 0a8c | ADD | |
| 0a8d | SWAP3 | |
| 0a8e | SWAP2 | |
| 0a8f | SWAP1 | |
| 0a90 | PUSH2 | 0x0883 |
| 0a93 | JUMP | |
| 0a94 | JUMPDEST | |
| 0a95 | PUSH2 | 0x0aa3 |
| 0a98 | DUP8 | |
| 0a99 | DUP8 | |
| 0a9a | PUSH2 | 0x0180 |
| 0a9d | MLOAD | |
| 0a9e | SWAP1 | |
| 0a9f | PUSH2 | 0x1721 |
| 0aa2 | JUMP | |
| 0aa3 | JUMPDEST | |
| 0aa4 | CALLDATALOAD | |
| 0aa5 | PUSH4 | 0x724ac173 |
| 0aaa | PUSH1 | 0xe0 |
| 0aac | SHL | |
| 0aad | PUSH2 | 0x0160 |
| 0ab0 | MLOAD | |
| 0ab1 | MSTORE | |
| 0ab2 | PUSH1 | 0x04 |
| 0ab4 | MSTORE | |
| 0ab5 | PUSH1 | 0x24 |
| 0ab7 | PUSH2 | 0x0160 |
| 0aba | MLOAD | |
| 0abb | REVERT | |
| 0abc | JUMPDEST | |
| 0abd | PUSH4 | 0x200ff7d7 |
| 0ac2 | PUSH1 | 0xe1 |
| 0ac4 | SHL | |
| 0ac5 | PUSH2 | 0x0160 |
| 0ac8 | MLOAD | |
| 0ac9 | MSTORE | |
| 0aca | PUSH1 | 0x04 |
| 0acc | PUSH2 | 0x0160 |
| 0acf | MLOAD | |
| 0ad0 | REVERT | |
| 0ad1 | JUMPDEST | |
| 0ad2 | POP | |
| 0ad3 | PUSH1 | 0x01 |
| 0ad5 | PUSH1 | 0x01 |
| 0ad7 | PUSH1 | 0x40 |
| 0ad9 | SHL | |
| 0ada | SUB | |
| 0adb | PUSH2 | 0x0aec |
| 0ade | PUSH2 | 0x0a63 |
| 0ae1 | DUP8 | |
| 0ae2 | PUSH1 | 0xa0 |
| 0ae4 | MLOAD | |
| 0ae5 | PUSH1 | 0x80 |
| 0ae7 | MLOAD | |
| 0ae8 | PUSH2 | 0x1721 |
| 0aeb | JUMP | |
| 0aec | JUMPDEST | |
| 0aed | AND | |
| 0aee | ISZERO | |
| 0aef | PUSH2 | 0x09fb |
| 0af2 | JUMP | |
| 0af3 | JUMPDEST | |
| 0af4 | POP | |
| 0af5 | PUSH1 | 0xa0 |
| 0af7 | MLOAD | |
| 0af8 | PUSH2 | 0x0180 |
| 0afb | MLOAD | |
| 0afc | EQ | |
| 0afd | ISZERO | |
| 0afe | PUSH2 | 0x0869 |
| 0b01 | JUMP | |
| 0b02 | JUMPDEST | |
| 0b03 | PUSH4 | 0xdc63d81f |
| 0b08 | PUSH1 | 0xe0 |
| 0b0a | SHL | |
| 0b0b | PUSH2 | 0x0160 |
| 0b0e | MLOAD | |
| 0b0f | MSTORE | |
| 0b10 | PUSH1 | 0x04 |
| 0b12 | PUSH2 | 0x0160 |
| 0b15 | MLOAD | |
| 0b16 | REVERT | |
| 0b17 | JUMPDEST | |
| 0b18 | POP | |
| 0b19 | PUSH1 | 0x05 |
| 0b1b | SLOAD | |
| 0b1c | ISZERO | |
| 0b1d | ISZERO | |
| 0b1e | PUSH2 | 0x0857 |
| 0b21 | JUMP | |
| 0b22 | JUMPDEST | |
| 0b23 | PUSH1 | 0x40 |
| 0b25 | MLOAD | |
| 0b26 | PUSH1 | 0xc0 |
| 0b28 | PUSH1 | 0x20 |
| 0b2a | DUP3 | |
| 0b2b | ADD | |
| 0b2c | MSTORE | |
| 0b2d | PUSH1 | 0x20 |
| 0b2f | PUSH2 | 0x0b55 |
| 0b32 | PUSH2 | 0x0b42 |
| 0b35 | PUSH1 | 0xe0 |
| 0b37 | DUP5 | |
| 0b38 | ADD | |
| 0b39 | PUSH2 | 0x0180 |
| 0b3c | MLOAD | |
| 0b3d | DUP11 | |
| 0b3e | PUSH2 | 0x16fd |
| 0b41 | JUMP | |
| 0b42 | JUMPDEST | |
| 0b43 | DUP4 | |
| 0b44 | DUP2 | |
| 0b45 | SUB | |
| 0b46 | PUSH1 | 0x1f |
| 0b48 | NOT | |
| 0b49 | ADD | |
| 0b4a | PUSH1 | 0x40 |
| 0b4c | DUP6 | |
| 0b4d | ADD | |
| 0b4e | MSTORE | |
| 0b4f | DUP8 | |
| 0b50 | DUP11 | |
| 0b51 | PUSH2 | 0x16fd |
| 0b54 | JUMP | |
| 0b55 | JUMPDEST | |
| 0b56 | PUSH1 | 0x1f |
| 0b58 | NOT | |
| 0b59 | DUP4 | |
| 0b5a | DUP3 | |
| 0b5b | SUB | |
| 0b5c | ADD | |
| 0b5d | PUSH1 | 0x60 |
| 0b5f | DUP5 | |
| 0b60 | ADD | |
| 0b61 | MSTORE | |
| 0b62 | PUSH1 | 0xa0 |
| 0b64 | MLOAD | |
| 0b65 | DUP2 | |
| 0b66 | MSTORE | |
| 0b67 | ADD | |
| 0b68 | DUP2 | |
| 0b69 | PUSH1 | 0x80 |
| 0b6b | MLOAD | |
| 0b6c | PUSH2 | 0x0160 |
| 0b6f | MLOAD | |
| 0b70 | JUMPDEST | |
| 0b71 | PUSH1 | 0xa0 |
| 0b73 | MLOAD | |
| 0b74 | DUP2 | |
| 0b75 | LT | |
| 0b76 | PUSH2 | 0x0da5 |
| 0b79 | JUMPI | |
| 0b7a | POP | |
| 0b7b | POP | |
| 0b7c | PUSH2 | 0x0bb5 |
| 0b7f | PUSH2 | 0x0b9e |
| 0b82 | PUSH2 | 0x0bd5 |
| 0b85 | SWAP4 | |
| 0b86 | PUSH1 | 0x1f |
| 0b88 | NOT | |
| 0b89 | DUP5 | |
| 0b8a | DUP3 | |
| 0b8b | SUB | |
| 0b8c | ADD | |
| 0b8d | PUSH1 | 0x80 |
| 0b8f | DUP6 | |
| 0b90 | ADD | |
| 0b91 | MSTORE | |
| 0b92 | PUSH2 | 0x0120 |
| 0b95 | MLOAD | |
| 0b96 | PUSH2 | 0x0100 |
| 0b99 | MLOAD | |
| 0b9a | PUSH2 | 0x16fd |
| 0b9d | JUMP | |
| 0b9e | JUMPDEST | |
| 0b9f | DUP3 | |
| 0ba0 | DUP2 | |
| 0ba1 | SUB | |
| 0ba2 | PUSH1 | 0x1f |
| 0ba4 | NOT | |
| 0ba5 | ADD | |
| 0ba6 | PUSH1 | 0xa0 |
| 0ba8 | DUP5 | |
| 0ba9 | ADD | |
| 0baa | MSTORE | |
| 0bab | PUSH1 | 0xc0 |
| 0bad | MLOAD | |
| 0bae | PUSH1 | 0xe0 |
| 0bb0 | MLOAD | |
| 0bb1 | PUSH2 | 0x16fd |
| 0bb4 | JUMP | |
| 0bb5 | JUMPDEST | |
| 0bb6 | PUSH1 | 0x01 |
| 0bb8 | PUSH1 | 0x01 |
| 0bba | PUSH1 | 0x40 |
| 0bbc | SHL | |
| 0bbd | SUB | |
| 0bbe | PUSH2 | 0x0140 |
| 0bc1 | MLOAD | |
| 0bc2 | AND | |
| 0bc3 | PUSH1 | 0xc0 |
| 0bc5 | DUP4 | |
| 0bc6 | ADD | |
| 0bc7 | MSTORE | |
| 0bc8 | SUB | |
| 0bc9 | PUSH1 | 0x1f |
| 0bcb | NOT | |
| 0bcc | DUP2 | |
| 0bcd | ADD | |
| 0bce | DUP4 | |
| 0bcf | MSTORE | |
| 0bd0 | DUP3 | |
| 0bd1 | PUSH2 | 0x1620 |
| 0bd4 | JUMP | |
| 0bd5 | JUMPDEST | |
| 0bd6 | DUP1 | |
| 0bd7 | MLOAD | |
| 0bd8 | PUSH1 | 0x20 |
| 0bda | SWAP1 | |
| 0bdb | SWAP2 | |
| 0bdc | ADD | |
| 0bdd | KECCAK256 | |
| 0bde | PUSH1 | 0x01 |
| 0be0 | PUSH1 | 0x01 |
| 0be2 | PUSH1 | 0xa0 |
| 0be4 | SHL | |
| 0be5 | SUB | |
| 0be6 | PUSH32 | 0x000000000000000000000000a2e71fc2fb02d1ce93aa958e56cab83d26f3bfa6 |
| 0c07 | AND | |
| 0c08 | EXTCODESIZE | |
| 0c09 | ISZERO | |
| 0c0a | PUSH2 | 0x012a |
| 0c0d | JUMPI | |
| 0c0e | DUP3 | |
| 0c0f | SWAP1 | |
| 0c10 | PUSH1 | 0x01 |
| 0c12 | PUSH1 | 0x01 |
| 0c14 | PUSH1 | 0x40 |
| 0c16 | SHL | |
| 0c17 | SUB | |
| 0c18 | PUSH1 | 0x40 |
| 0c1a | MLOAD | |
| 0c1b | SWAP6 | |
| 0c1c | PUSH4 | 0x22f3f447 |
| 0c21 | PUSH1 | 0xe1 |
| 0c23 | SHL | |
| 0c24 | DUP8 | |
| 0c25 | MSTORE | |
| 0c26 | PUSH2 | 0x0160 |
| 0c29 | MLOAD | |
| 0c2a | POP | |
| 0c2b | PUSH1 | 0x84 |
| 0c2d | DUP8 | |
| 0c2e | ADD | |
| 0c2f | SWAP3 | |
| 0c30 | PUSH32 | 0x08296c4851c7aca93c422c73902d61d179ed1bf52cf0ed257e6d096b9a8bb851 |
| 0c51 | PUSH1 | 0x04 |
| 0c53 | DUP10 | |
| 0c54 | ADD | |
| 0c55 | MSTORE | |
| 0c56 | PUSH1 | 0x24 |
| 0c58 | DUP9 | |
| 0c59 | ADD | |
| 0c5a | MSTORE | |
| 0c5b | AND | |
| 0c5c | PUSH1 | 0x44 |
| 0c5e | DUP7 | |
| 0c5f | ADD | |
| 0c60 | MSTORE | |
| 0c61 | PUSH1 | 0x80 |
| 0c63 | PUSH1 | 0x64 |
| 0c65 | DUP7 | |
| 0c66 | ADD | |
| 0c67 | MSTORE | |
| 0c68 | MSTORE | |
| 0c69 | PUSH1 | 0xa4 |
| 0c6b | DUP4 | |
| 0c6c | ADD | |
| 0c6d | PUSH1 | 0xa0 |
| 0c6f | PUSH1 | 0x04 |
| 0c71 | DUP5 | |
| 0c72 | PUSH1 | 0x05 |
| 0c74 | SHL | |
| 0c75 | DUP7 | |
| 0c76 | ADD | |
| 0c77 | ADD | |
| 0c78 | ADD | |
| 0c79 | SWAP3 | |
| 0c7a | DUP3 | |
| 0c7b | PUSH2 | 0x0160 |
| 0c7e | MLOAD | |
| 0c7f | SWAP1 | |
| 0c80 | JUMPDEST | |
| 0c81 | DUP3 | |
| 0c82 | DUP3 | |
| 0c83 | LT | |
| 0c84 | PUSH2 | 0x0d01 |
| 0c87 | JUMPI | |
| 0c88 | POP | |
| 0c89 | POP | |
| 0c8a | PUSH2 | 0x0160 |
| 0c8d | MLOAD | |
| 0c8e | SWAP4 | |
| 0c8f | DUP6 | |
| 0c90 | SWAP4 | |
| 0c91 | POP | |
| 0c92 | DUP4 | |
| 0c93 | SWAP1 | |
| 0c94 | SUB | |
| 0c95 | SWAP2 | |
| 0c96 | POP | |
| 0c97 | DUP3 | |
| 0c98 | SWAP1 | |
| 0c99 | POP | |
| 0c9a | DUP4 | |
| 0c9b | PUSH32 | 0x000000000000000000000000a2e71fc2fb02d1ce93aa958e56cab83d26f3bfa6 |
| 0cbc | PUSH1 | 0x01 |
| 0cbe | PUSH1 | 0x01 |
| 0cc0 | PUSH1 | 0xa0 |
| 0cc2 | SHL | |
| 0cc3 | SUB | |
| 0cc4 | AND | |
| 0cc5 | GAS | |
| 0cc6 | CALL | |
| 0cc7 | DUP1 | |
| 0cc8 | ISZERO | |
| 0cc9 | PUSH2 | 0x0cf3 |
| 0ccc | JUMPI | |
| 0ccd | PUSH2 | 0x0cd8 |
| 0cd0 | JUMPI | |
| 0cd1 | JUMPDEST | |
| 0cd2 | DUP1 | |
| 0cd3 | DUP1 | |
| 0cd4 | PUSH2 | 0x083f |
| 0cd7 | JUMP | |
| 0cd8 | JUMPDEST | |
| 0cd9 | PUSH2 | 0x0160 |
| 0cdc | MLOAD | |
| 0cdd | PUSH2 | 0x0ce5 |
| 0ce0 | SWAP2 | |
| 0ce1 | PUSH2 | 0x1620 |
| 0ce4 | JUMP | |
| 0ce5 | JUMPDEST | |
| 0ce6 | PUSH2 | 0x0160 |
| 0ce9 | MLOAD | |
| 0cea | PUSH2 | 0x012a |
| 0ced | JUMPI | |
| 0cee | DUP4 | |
| 0cef | PUSH2 | 0x0cd1 |
| 0cf2 | JUMP | |
| 0cf3 | JUMPDEST | |
| 0cf4 | PUSH1 | 0x40 |
| 0cf6 | MLOAD | |
| 0cf7 | RETURNDATASIZE | |
| 0cf8 | PUSH2 | 0x0160 |
| 0cfb | MLOAD | |
| 0cfc | DUP3 | |
| 0cfd | RETURNDATACOPY | |
| 0cfe | RETURNDATASIZE | |
| 0cff | SWAP1 | |
| 0d00 | REVERT | |
| 0d01 | JUMPDEST | |
| 0d02 | SWAP1 | |
| 0d03 | SWAP2 | |
| 0d04 | SWAP3 | |
| 0d05 | SWAP4 | |
| 0d06 | SWAP5 | |
| 0d07 | PUSH1 | 0x9f |
| 0d09 | NOT | |
| 0d0a | PUSH1 | 0x03 |
| 0d0c | NOT | |
| 0d0d | DUP9 | |
| 0d0e | DUP4 | |
| 0d0f | SUB | |
| 0d10 | ADD | |
| 0d11 | ADD | |
| 0d12 | DUP6 | |
| 0d13 | MSTORE | |
| 0d14 | DUP6 | |
| 0d15 | CALLDATALOAD | |
| 0d16 | PUSH1 | 0x7e |
| 0d18 | NOT | |
| 0d19 | DUP4 | |
| 0d1a | CALLDATASIZE | |
| 0d1b | SUB | |
| 0d1c | ADD | |
| 0d1d | DUP2 | |
| 0d1e | SLT | |
| 0d1f | ISZERO | |
| 0d20 | PUSH2 | 0x012a |
| 0d23 | JUMPI | |
| 0d24 | DUP3 | |
| 0d25 | ADD | |
| 0d26 | DUP1 | |
| 0d27 | CALLDATALOAD | |
| 0d28 | PUSH1 | 0x01 |
| 0d2a | PUSH1 | 0x01 |
| 0d2c | PUSH1 | 0xa0 |
| 0d2e | SHL | |
| 0d2f | SUB | |
| 0d30 | DUP2 | |
| 0d31 | AND | |
| 0d32 | SWAP1 | |
| 0d33 | DUP2 | |
| 0d34 | SWAP1 | |
| 0d35 | SUB | |
| 0d36 | PUSH2 | 0x012a |
| 0d39 | JUMPI | |
| 0d3a | DUP3 | |
| 0d3b | MSTORE | |
| 0d3c | PUSH1 | 0x20 |
| 0d3e | DUP2 | |
| 0d3f | ADD | |
| 0d40 | CALLDATALOAD | |
| 0d41 | SWAP2 | |
| 0d42 | PUSH1 | 0xff |
| 0d44 | DUP4 | |
| 0d45 | AND | |
| 0d46 | DUP1 | |
| 0d47 | SWAP4 | |
| 0d48 | SUB | |
| 0d49 | PUSH2 | 0x012a |
| 0d4c | JUMPI | |
| 0d4d | PUSH2 | 0x0d98 |
| 0d50 | PUSH1 | 0x20 |
| 0d52 | SWAP3 | |
| 0d53 | DUP3 | |
| 0d54 | PUSH1 | 0x01 |
| 0d56 | SWAP6 | |
| 0d57 | DUP6 | |
| 0d58 | DUP1 | |
| 0d59 | SWAP6 | |
| 0d5a | ADD | |
| 0d5b | MSTORE | |
| 0d5c | PUSH2 | 0x0d8a |
| 0d5f | PUSH2 | 0x0d7f |
| 0d62 | PUSH2 | 0x0d6e |
| 0d65 | PUSH1 | 0x40 |
| 0d67 | DUP6 | |
| 0d68 | ADD | |
| 0d69 | DUP6 | |
| 0d6a | PUSH2 | 0x1694 |
| 0d6d | JUMP | |
| 0d6e | JUMPDEST | |
| 0d6f | PUSH1 | 0x80 |
| 0d71 | PUSH1 | 0x40 |
| 0d73 | DUP7 | |
| 0d74 | ADD | |
| 0d75 | MSTORE | |
| 0d76 | PUSH1 | 0x80 |
| 0d78 | DUP6 | |
| 0d79 | ADD | |
| 0d7a | SWAP2 | |
| 0d7b | PUSH2 | 0x16c5 |
| 0d7e | JUMP | |
| 0d7f | JUMPDEST | |
| 0d80 | SWAP3 | |
| 0d81 | PUSH1 | 0x60 |
| 0d83 | DUP2 | |
| 0d84 | ADD | |
| 0d85 | SWAP1 | |
| 0d86 | PUSH2 | 0x1694 |
| 0d89 | JUMP | |
| 0d8a | JUMPDEST | |
| 0d8b | SWAP2 | |
| 0d8c | PUSH1 | 0x60 |
| 0d8e | DUP2 | |
| 0d8f | DUP6 | |
| 0d90 | SUB | |
| 0d91 | SWAP2 | |
| 0d92 | ADD | |
| 0d93 | MSTORE | |
| 0d94 | PUSH2 | 0x16c5 |
| 0d97 | JUMP | |
| 0d98 | JUMPDEST | |
| 0d99 | SWAP8 | |
| 0d9a | ADD | |
| 0d9b | SWAP6 | |
| 0d9c | ADD | |
| 0d9d | SWAP4 | |
| 0d9e | SWAP3 | |
| 0d9f | ADD | |
| 0da0 | SWAP1 | |
| 0da1 | PUSH2 | 0x0c80 |
| 0da4 | JUMP | |
| 0da5 | JUMPDEST | |
| 0da6 | SWAP2 | |
| 0da7 | POP | |
| 0da8 | SWAP2 | |
| 0da9 | PUSH2 | 0x0160 |
| 0dac | MLOAD | |
| 0dad | POP | |
| 0dae | DUP3 | |
| 0daf | CALLDATALOAD | |
| 0db0 | SWAP1 | |
| 0db1 | PUSH1 | 0x01 |
| 0db3 | PUSH1 | 0x01 |
| 0db5 | PUSH1 | 0x40 |
| 0db7 | SHL | |
| 0db8 | SUB | |
| 0db9 | DUP3 | |
| 0dba | AND | |
| 0dbb | DUP1 | |
| 0dbc | SWAP3 | |
| 0dbd | SUB | |
| 0dbe | PUSH2 | 0x012a |
| 0dc1 | JUMPI | |
| 0dc2 | PUSH1 | 0x20 |
| 0dc4 | DUP2 | |
| 0dc5 | PUSH1 | 0x01 |
| 0dc7 | SWAP4 | |
| 0dc8 | DUP3 | |
| 0dc9 | SWAP4 | |
| 0dca | MSTORE | |
| 0dcb | ADD | |
| 0dcc | SWAP4 | |
| 0dcd | ADD | |
| 0dce | SWAP2 | |
| 0dcf | ADD | |
| 0dd0 | SWAP1 | |
| 0dd1 | DUP4 | |
| 0dd2 | SWAP2 | |
| 0dd3 | PUSH2 | 0x0b70 |
| 0dd6 | JUMP | |
| 0dd7 | JUMPDEST | |
| 0dd8 | POP | |
| 0dd9 | PUSH1 | 0x40 |
| 0ddb | MLOAD | |
| 0ddc | PUSH4 | 0xf5778b03 |
| 0de1 | PUSH1 | 0xe0 |
| 0de3 | SHL | |
| 0de4 | DUP2 | |
| 0de5 | MSTORE | |
| 0de6 | PUSH1 | 0x20 |
| 0de8 | DUP2 | |
| 0de9 | PUSH1 | 0x04 |
| 0deb | DUP2 | |
| 0dec | PUSH32 | 0x000000000000000000000000a2e71fc2fb02d1ce93aa958e56cab83d26f3bfa6 |
| 0e0d | PUSH1 | 0x01 |
| 0e0f | PUSH1 | 0x01 |
| 0e11 | PUSH1 | 0xa0 |
| 0e13 | SHL | |
| 0e14 | SUB | |
| 0e15 | AND | |
| 0e16 | GAS | |
| 0e17 | STATICCALL | |
| 0e18 | SWAP1 | |
| 0e19 | DUP2 | |
| 0e1a | ISZERO | |
| 0e1b | PUSH2 | 0x0cf3 |
| 0e1e | JUMPI | |
| 0e1f | PUSH2 | 0x0160 |
| 0e22 | MLOAD | |
| 0e23 | SWAP2 | |
| 0e24 | PUSH2 | 0x0e3a |
| 0e27 | JUMPI | |
| 0e28 | JUMPDEST | |
| 0e29 | POP | |
| 0e2a | PUSH1 | 0x01 |
| 0e2c | PUSH1 | 0x01 |
| 0e2e | PUSH1 | 0xa0 |
| 0e30 | SHL | |
| 0e31 | SUB | |
| 0e32 | AND | |
| 0e33 | CALLER | |
| 0e34 | EQ | |
| 0e35 | ISZERO | |
| 0e36 | PUSH2 | 0x083a |
| 0e39 | JUMP | |
| 0e3a | JUMPDEST | |
| 0e3b | SWAP1 | |
| 0e3c | POP | |
| 0e3d | PUSH1 | 0x20 |
| 0e3f | DUP2 | |
| 0e40 | RETURNDATASIZE | |
| 0e41 | PUSH1 | 0x20 |
| 0e43 | GT | |
| 0e44 | PUSH2 | 0x0e74 |
| 0e47 | JUMPI | |
| 0e48 | JUMPDEST | |
| 0e49 | DUP2 | |
| 0e4a | PUSH2 | 0x0e55 |
| 0e4d | PUSH1 | 0x20 |
| 0e4f | SWAP4 | |
| 0e50 | DUP4 | |
| 0e51 | PUSH2 | 0x1620 |
| 0e54 | JUMP | |
| 0e55 | JUMPDEST | |
| 0e56 | DUP2 | |
| 0e57 | ADD | |
| 0e58 | SUB | |
| 0e59 | SLT | |
| 0e5a | PUSH2 | 0x012a |
| 0e5d | JUMPI | |
| 0e5e | MLOAD | |
| 0e5f | PUSH1 | 0x01 |
| 0e61 | PUSH1 | 0x01 |
| 0e63 | PUSH1 | 0xa0 |
| 0e65 | SHL | |
| 0e66 | SUB | |
| 0e67 | DUP2 | |
| 0e68 | AND | |
| 0e69 | DUP2 | |
| 0e6a | SUB | |
| 0e6b | PUSH2 | 0x012a |
| 0e6e | JUMPI | |
| 0e6f | DUP8 | |
| 0e70 | PUSH2 | 0x0e28 |
| 0e73 | JUMP | |
| 0e74 | JUMPDEST | |
| 0e75 | RETURNDATASIZE | |
| 0e76 | SWAP2 | |
| 0e77 | POP | |
| 0e78 | PUSH2 | 0x0e48 |
| 0e7b | JUMP | |
| 0e7c | JUMPDEST | |
| 0e7d | PUSH2 | 0x0e9e |
| 0e80 | SWAP2 | |
| 0e81 | POP | |
| 0e82 | PUSH1 | 0x20 |
| 0e84 | RETURNDATASIZE | |
| 0e85 | PUSH1 | 0x20 |
| 0e87 | GT | |
| 0e88 | PUSH2 | 0x0ea4 |
| 0e8b | JUMPI | |
| 0e8c | JUMPDEST | |
| 0e8d | PUSH2 | 0x0e96 |
| 0e90 | DUP2 | |
| 0e91 | DUP4 | |
| 0e92 | PUSH2 | 0x1620 |
| 0e95 | JUMP | |
| 0e96 | JUMPDEST | |
| 0e97 | DUP2 | |
| 0e98 | ADD | |
| 0e99 | SWAP1 | |
| 0e9a | PUSH2 | 0x16e5 |
| 0e9d | JUMP | |
| 0e9e | JUMPDEST | |
| 0e9f | DUP8 | |
| 0ea0 | PUSH2 | 0x0832 |
| 0ea3 | JUMP | |
| 0ea4 | JUMPDEST | |
| 0ea5 | POP | |
| 0ea6 | RETURNDATASIZE | |
| 0ea7 | PUSH2 | 0x0e8c |
| 0eaa | JUMP | |
| 0eab | JUMPDEST | |
| 0eac | CALLVALUE | |
| 0ead | PUSH2 | 0x1189 |
| 0eb0 | JUMPI | |
| 0eb1 | PUSH1 | 0x80 |
| 0eb3 | CALLDATASIZE | |
| 0eb4 | PUSH1 | 0x03 |
| 0eb6 | NOT | |
| 0eb7 | ADD | |
| 0eb8 | SLT | |
| 0eb9 | PUSH2 | 0x1189 |
| 0ebc | JUMPI | |
| 0ebd | PUSH1 | 0x24 |
| 0ebf | CALLDATALOAD | |
| 0ec0 | PUSH1 | 0x04 |
| 0ec2 | CALLDATALOAD | |
| 0ec3 | PUSH2 | 0x0eca |
| 0ec6 | PUSH2 | 0x15da |
| 0ec9 | JUMP | |
| 0eca | JUMPDEST | |
| 0ecb | PUSH1 | 0x64 |
| 0ecd | CALLDATALOAD | |
| 0ece | PUSH1 | 0x01 |
| 0ed0 | PUSH1 | 0x01 |
| 0ed2 | PUSH1 | 0x40 |
| 0ed4 | SHL | |
| 0ed5 | SUB | |
| 0ed6 | DUP2 | |
| 0ed7 | GT | |
| 0ed8 | PUSH2 | 0x1189 |
| 0edb | JUMPI | |
| 0edc | PUSH2 | 0x0ee9 |
| 0edf | SWAP1 | |
| 0ee0 | CALLDATASIZE | |
| 0ee1 | SWAP1 | |
| 0ee2 | PUSH1 | 0x04 |
| 0ee4 | ADD | |
| 0ee5 | PUSH2 | 0x15f0 |
| 0ee8 | JUMP | |
| 0ee9 | JUMPDEST | |
| 0eea | PUSH0 | |
| 0eeb | SLOAD | |
| 0eec | PUSH1 | 0x01 |
| 0eee | PUSH1 | 0x01 |
| 0ef0 | PUSH1 | 0xa0 |
| 0ef2 | SHL | |
| 0ef3 | SUB | |
| 0ef4 | AND | |
| 0ef5 | CALLER | |
| 0ef6 | SUB | |
| 0ef7 | PUSH2 | 0x0ff7 |
| 0efa | JUMPI | |
| 0efb | JUMPDEST | |
| 0efc | POP | |
| 0efd | POP | |
| 0efe | POP | |
| 0eff | DUP2 | |
| 0f00 | PUSH2 | 0x0f43 |
| 0f03 | JUMPI | |
| 0f04 | JUMPDEST | |
| 0f05 | DUP1 | |
| 0f06 | PUSH32 | 0x43c4ef2494de90aa2f24830e48f3dc8579dec67c48d59b2ffba50c125576d4c4 |
| 0f27 | SWAP3 | |
| 0f28 | PUSH1 | 0x40 |
| 0f2a | SWAP3 | |
| 0f2b | PUSH1 | 0x01 |
| 0f2d | SSTORE | |
| 0f2e | DUP1 | |
| 0f2f | PUSH1 | 0x02 |
| 0f31 | SSTORE | |
| 0f32 | DUP3 | |
| 0f33 | MLOAD | |
| 0f34 | SWAP2 | |
| 0f35 | DUP3 | |
| 0f36 | MSTORE | |
| 0f37 | PUSH1 | 0x20 |
| 0f39 | DUP3 | |
| 0f3a | ADD | |
| 0f3b | MSTORE | |
| 0f3c | LOG1 | |
| 0f3d | PUSH2 | 0x0160 |
| 0f40 | MLOAD | |
| 0f41 | DUP1 | |
| 0f42 | RETURN | |
| 0f43 | JUMPDEST | |
| 0f44 | PUSH1 | 0x40 |
| 0f46 | MLOAD | |
| 0f47 | PUSH4 | 0x342f6163 |
| 0f4c | PUSH1 | 0xe0 |
| 0f4e | SHL | |
| 0f4f | DUP2 | |
| 0f50 | MSTORE | |
| 0f51 | PUSH1 | 0x04 |
| 0f53 | DUP2 | |
| 0f54 | ADD | |
| 0f55 | DUP3 | |
| 0f56 | SWAP1 | |
| 0f57 | MSTORE | |
| 0f58 | PUSH1 | 0x20 |
| 0f5a | DUP2 | |
| 0f5b | PUSH1 | 0x24 |
| 0f5d | DUP2 | |
| 0f5e | PUSH32 | 0x000000000000000000000000a2e71fc2fb02d1ce93aa958e56cab83d26f3bfa6 |
| 0f7f | PUSH1 | 0x01 |
| 0f81 | PUSH1 | 0x01 |
| 0f83 | PUSH1 | 0xa0 |
| 0f85 | SHL | |
| 0f86 | SUB | |
| 0f87 | AND | |
| 0f88 | GAS | |
| 0f89 | STATICCALL | |
| 0f8a | SWAP1 | |
| 0f8b | DUP2 | |
| 0f8c | ISZERO | |
| 0f8d | PUSH2 | 0x0cf3 |
| 0f90 | JUMPI | |
| 0f91 | PUSH2 | 0x0160 |
| 0f94 | MLOAD | |
| 0f95 | SWAP2 | |
| 0f96 | PUSH2 | 0x0fc5 |
| 0f99 | JUMPI | |
| 0f9a | JUMPDEST | |
| 0f9b | POP | |
| 0f9c | DUP3 | |
| 0f9d | DUP2 | |
| 0f9e | LT | |
| 0f9f | PUSH2 | 0x0fa8 |
| 0fa2 | JUMPI | |
| 0fa3 | POP | |
| 0fa4 | PUSH2 | 0x0f04 |
| 0fa7 | JUMP | |
| 0fa8 | JUMPDEST | |
| 0fa9 | SWAP1 | |
| 0faa | POP | |
| 0fab | PUSH4 | 0x3770da33 |
| 0fb0 | PUSH1 | 0xe1 |
| 0fb2 | SHL | |
| 0fb3 | PUSH2 | 0x0160 |
| 0fb6 | MLOAD | |
| 0fb7 | MSTORE | |
| 0fb8 | PUSH1 | 0x04 |
| 0fba | MSTORE | |
| 0fbb | PUSH1 | 0x24 |
| 0fbd | MSTORE | |
| 0fbe | PUSH1 | 0x44 |
| 0fc0 | PUSH2 | 0x0160 |
| 0fc3 | MLOAD | |
| 0fc4 | REVERT | |
| 0fc5 | JUMPDEST | |
| 0fc6 | SWAP1 | |
| 0fc7 | POP | |
| 0fc8 | PUSH1 | 0x20 |
| 0fca | DUP2 | |
| 0fcb | RETURNDATASIZE | |
| 0fcc | PUSH1 | 0x20 |
| 0fce | GT | |
| 0fcf | PUSH2 | 0x0fef |
| 0fd2 | JUMPI | |
| 0fd3 | JUMPDEST | |
| 0fd4 | DUP2 | |
| 0fd5 | PUSH2 | 0x0fe0 |
| 0fd8 | PUSH1 | 0x20 |
| 0fda | SWAP4 | |
| 0fdb | DUP4 | |
| 0fdc | PUSH2 | 0x1620 |
| 0fdf | JUMP | |
| 0fe0 | JUMPDEST | |
| 0fe1 | DUP2 | |
| 0fe2 | ADD | |
| 0fe3 | SUB | |
| 0fe4 | SLT | |
| 0fe5 | PUSH2 | 0x012a |
| 0fe8 | JUMPI | |
| 0fe9 | MLOAD | |
| 0fea | DUP4 | |
| 0feb | PUSH2 | 0x0f9a |
| 0fee | JUMP | |
| 0fef | JUMPDEST | |
| 0ff0 | RETURNDATASIZE | |
| 0ff1 | SWAP2 | |
| 0ff2 | POP | |
| 0ff3 | PUSH2 | 0x0fd3 |
| 0ff6 | JUMP | |
| 0ff7 | JUMPDEST | |
| 0ff8 | PUSH1 | 0x40 |
| 0ffa | DUP1 | |
| 0ffb | MLOAD | |
| 0ffc | PUSH1 | 0x20 |
| 0ffe | DUP2 | |
| 0fff | ADD | |
| 1000 | DUP7 | |
| 1001 | DUP2 | |
| 1002 | MSTORE | |
| 1003 | DUP2 | |
| 1004 | DUP4 | |
| 1005 | ADD | |
| 1006 | DUP9 | |
| 1007 | SWAP1 | |
| 1008 | MSTORE | |
| 1009 | SWAP2 | |
| 100a | DUP2 | |
| 100b | MSTORE | |
| 100c | PUSH32 | 0x000000000000000000000000a2e71fc2fb02d1ce93aa958e56cab83d26f3bfa6 |
| 102d | PUSH1 | 0x01 |
| 102f | PUSH1 | 0x01 |
| 1031 | PUSH1 | 0xa0 |
| 1033 | SHL | |
| 1034 | SUB | |
| 1035 | AND | |
| 1036 | SWAP4 | |
| 1037 | SWAP2 | |
| 1038 | SWAP1 | |
| 1039 | PUSH2 | 0x1043 |
| 103c | PUSH1 | 0x60 |
| 103e | DUP3 | |
| 103f | PUSH2 | 0x1620 |
| 1042 | JUMP | |
| 1043 | JUMPDEST | |
| 1044 | MLOAD | |
| 1045 | SWAP1 | |
| 1046 | KECCAK256 | |
| 1047 | DUP4 | |
| 1048 | EXTCODESIZE | |
| 1049 | ISZERO | |
| 104a | PUSH2 | 0x1189 |
| 104d | JUMPI | |
| 104e | SWAP1 | |
| 104f | DUP3 | |
| 1050 | PUSH1 | 0x01 |
| 1052 | PUSH1 | 0x01 |
| 1054 | PUSH1 | 0x40 |
| 1056 | SHL | |
| 1057 | SUB | |
| 1058 | SWAP6 | |
| 1059 | SWAP4 | |
| 105a | SWAP3 | |
| 105b | PUSH1 | 0x40 |
| 105d | MLOAD | |
| 105e | SWAP7 | |
| 105f | DUP8 | |
| 1060 | SWAP6 | |
| 1061 | PUSH4 | 0x22f3f447 |
| 1066 | PUSH1 | 0xe1 |
| 1068 | SHL | |
| 1069 | DUP8 | |
| 106a | MSTORE | |
| 106b | PUSH1 | 0x84 |
| 106d | DUP8 | |
| 106e | ADD | |
| 106f | SWAP3 | |
| 1070 | PUSH32 | 0xbc5858e168b959a61a8fb2d7957ef31dbed683a362770ca030e5d772cc44e068 |
| 1091 | PUSH1 | 0x04 |
| 1093 | DUP10 | |
| 1094 | ADD | |
| 1095 | MSTORE | |
| 1096 | PUSH1 | 0x24 |
| 1098 | DUP9 | |
| 1099 | ADD | |
| 109a | MSTORE | |
| 109b | AND | |
| 109c | PUSH1 | 0x44 |
| 109e | DUP7 | |
| 109f | ADD | |
| 10a0 | MSTORE | |
| 10a1 | PUSH1 | 0x80 |
| 10a3 | PUSH1 | 0x64 |
| 10a5 | DUP7 | |
| 10a6 | ADD | |
| 10a7 | MSTORE | |
| 10a8 | MSTORE | |
| 10a9 | PUSH1 | 0xa4 |
| 10ab | DUP4 | |
| 10ac | ADD | |
| 10ad | PUSH1 | 0xa0 |
| 10af | PUSH1 | 0x04 |
| 10b1 | DUP5 | |
| 10b2 | PUSH1 | 0x05 |
| 10b4 | SHL | |
| 10b5 | DUP7 | |
| 10b6 | ADD | |
| 10b7 | ADD | |
| 10b8 | ADD | |
| 10b9 | SWAP3 | |
| 10ba | DUP3 | |
| 10bb | PUSH0 | |
| 10bc | SWAP1 | |
| 10bd | PUSH1 | 0x7e |
| 10bf | NOT | |
| 10c0 | DUP2 | |
| 10c1 | CALLDATASIZE | |
| 10c2 | SUB | |
| 10c3 | ADD | |
| 10c4 | JUMPDEST | |
| 10c5 | DUP4 | |
| 10c6 | DUP4 | |
| 10c7 | LT | |
| 10c8 | PUSH2 | 0x110f |
| 10cb | JUMPI | |
| 10cc | POP | |
| 10cd | POP | |
| 10ce | POP | |
| 10cf | POP | |
| 10d0 | POP | |
| 10d1 | POP | |
| 10d2 | SWAP2 | |
| 10d3 | DUP2 | |
| 10d4 | PUSH0 | |
| 10d5 | DUP2 | |
| 10d6 | DUP6 | |
| 10d7 | DUP3 | |
| 10d8 | SWAP7 | |
| 10d9 | POP | |
| 10da | SUB | |
| 10db | SWAP3 | |
| 10dc | GAS | |
| 10dd | CALL | |
| 10de | DUP1 | |
| 10df | ISZERO | |
| 10e0 | PUSH2 | 0x1104 |
| 10e3 | JUMPI | |
| 10e4 | PUSH2 | 0x10ef |
| 10e7 | JUMPI | |
| 10e8 | JUMPDEST | |
| 10e9 | DUP1 | |
| 10ea | DUP1 | |
| 10eb | PUSH2 | 0x0efb |
| 10ee | JUMP | |
| 10ef | JUMPDEST | |
| 10f0 | PUSH0 | |
| 10f1 | PUSH2 | 0x10f9 |
| 10f4 | SWAP2 | |
| 10f5 | PUSH2 | 0x1620 |
| 10f8 | JUMP | |
| 10f9 | JUMPDEST | |
| 10fa | PUSH0 | |
| 10fb | PUSH2 | 0x0160 |
| 10fe | MSTORE | |
| 10ff | DUP3 | |
| 1100 | PUSH2 | 0x10e8 |
| 1103 | JUMP | |
| 1104 | JUMPDEST | |
| 1105 | PUSH1 | 0x40 |
| 1107 | MLOAD | |
| 1108 | RETURNDATASIZE | |
| 1109 | PUSH0 | |
| 110a | DUP3 | |
| 110b | RETURNDATACOPY | |
| 110c | RETURNDATASIZE | |
| 110d | SWAP1 | |
| 110e | REVERT | |
| 110f | JUMPDEST | |
| 1110 | PUSH1 | 0xa3 |
| 1112 | NOT | |
| 1113 | DUP11 | |
| 1114 | DUP9 | |
| 1115 | SUB | |
| 1116 | ADD | |
| 1117 | DUP6 | |
| 1118 | MSTORE | |
| 1119 | SWAP5 | |
| 111a | SWAP7 | |
| 111b | POP | |
| 111c | SWAP3 | |
| 111d | SWAP5 | |
| 111e | SWAP2 | |
| 111f | SWAP4 | |
| 1120 | SWAP1 | |
| 1121 | SWAP3 | |
| 1122 | SWAP2 | |
| 1123 | DUP7 | |
| 1124 | CALLDATALOAD | |
| 1125 | DUP3 | |
| 1126 | DUP2 | |
| 1127 | SLT | |
| 1128 | ISZERO | |
| 1129 | PUSH2 | 0x1189 |
| 112c | JUMPI | |
| 112d | DUP4 | |
| 112e | ADD | |
| 112f | DUP1 | |
| 1130 | CALLDATALOAD | |
| 1131 | PUSH1 | 0x01 |
| 1133 | PUSH1 | 0x01 |
| 1135 | PUSH1 | 0xa0 |
| 1137 | SHL | |
| 1138 | SUB | |
| 1139 | DUP2 | |
| 113a | AND | |
| 113b | SWAP1 | |
| 113c | DUP2 | |
| 113d | SWAP1 | |
| 113e | SUB | |
| 113f | PUSH2 | 0x1189 |
| 1142 | JUMPI | |
| 1143 | DUP3 | |
| 1144 | MSTORE | |
| 1145 | PUSH1 | 0x20 |
| 1147 | DUP2 | |
| 1148 | ADD | |
| 1149 | CALLDATALOAD | |
| 114a | SWAP2 | |
| 114b | PUSH1 | 0xff |
| 114d | DUP4 | |
| 114e | AND | |
| 114f | DUP1 | |
| 1150 | SWAP4 | |
| 1151 | SUB | |
| 1152 | PUSH2 | 0x1189 |
| 1155 | JUMPI | |
| 1156 | PUSH2 | 0x1177 |
| 1159 | PUSH1 | 0x20 |
| 115b | SWAP3 | |
| 115c | DUP3 | |
| 115d | PUSH1 | 0x01 |
| 115f | SWAP6 | |
| 1160 | DUP6 | |
| 1161 | DUP1 | |
| 1162 | SWAP6 | |
| 1163 | ADD | |
| 1164 | MSTORE | |
| 1165 | PUSH2 | 0x0d8a |
| 1168 | PUSH2 | 0x0d7f |
| 116b | PUSH2 | 0x0d6e |
| 116e | PUSH1 | 0x40 |
| 1170 | DUP6 | |
| 1171 | ADD | |
| 1172 | DUP6 | |
| 1173 | PUSH2 | 0x1694 |
| 1176 | JUMP | |
| 1177 | JUMPDEST | |
| 1178 | SWAP9 | |
| 1179 | ADD | |
| 117a | SWAP7 | |
| 117b | ADD | |
| 117c | SWAP4 | |
| 117d | ADD | |
| 117e | SWAP1 | |
| 117f | SWAP2 | |
| 1180 | DUP9 | |
| 1181 | SWAP7 | |
| 1182 | SWAP6 | |
| 1183 | SWAP5 | |
| 1184 | SWAP3 | |
| 1185 | PUSH2 | 0x10c4 |
| 1188 | JUMP | |
| 1189 | JUMPDEST | |
| 118a | PUSH0 | |
| 118b | DUP1 | |
| 118c | REVERT | |
| 118d | JUMPDEST | |
| 118e | CALLVALUE | |
| 118f | PUSH2 | 0x1189 |
| 1192 | JUMPI | |
| 1193 | PUSH0 | |
| 1194 | CALLDATASIZE | |
| 1195 | PUSH1 | 0x03 |
| 1197 | NOT | |
| 1198 | ADD | |
| 1199 | SLT | |
| 119a | PUSH2 | 0x1189 |
| 119d | JUMPI | |
| 119e | PUSH1 | 0x20 |
| 11a0 | PUSH1 | 0x40 |
| 11a2 | MLOAD | |
| 11a3 | PUSH11 | 0x52b7d2dcc80cd2e4000000 |
| 11af | DUP2 | |
| 11b0 | MSTORE | |
| 11b1 | RETURN | |
| 11b2 | JUMPDEST | |
| 11b3 | CALLVALUE | |
| 11b4 | PUSH2 | 0x1189 |
| 11b7 | JUMPI | |
| 11b8 | PUSH0 | |
| 11b9 | CALLDATASIZE | |
| 11ba | PUSH1 | 0x03 |
| 11bc | NOT | |
| 11bd | ADD | |
| 11be | SLT | |
| 11bf | PUSH2 | 0x1189 |
| 11c2 | JUMPI | |
| 11c3 | PUSH1 | 0x20 |
| 11c5 | PUSH2 | 0x11d3 |
| 11c8 | PUSH1 | 0x03 |
| 11ca | SLOAD | |
| 11cb | PUSH1 | 0x05 |
| 11cd | SLOAD | |
| 11ce | SWAP1 | |
| 11cf | PUSH2 | 0x1687 |
| 11d2 | JUMP | |
| 11d3 | JUMPDEST | |
| 11d4 | PUSH1 | 0x40 |
| 11d6 | MLOAD | |
| 11d7 | SWAP1 | |
| 11d8 | DUP2 | |
| 11d9 | MSTORE | |
| 11da | RETURN | |
| 11db | JUMPDEST | |
| 11dc | CALLVALUE | |
| 11dd | PUSH2 | 0x1189 |
| 11e0 | JUMPI | |
| 11e1 | PUSH1 | 0x20 |
| 11e3 | CALLDATASIZE | |
| 11e4 | PUSH1 | 0x03 |
| 11e6 | NOT | |
| 11e7 | ADD | |
| 11e8 | SLT | |
| 11e9 | PUSH2 | 0x1189 |
| 11ec | JUMPI | |
| 11ed | PUSH1 | 0x04 |
| 11ef | CALLDATALOAD | |
| 11f0 | PUSH0 | |
| 11f1 | MSTORE | |
| 11f2 | PUSH1 | 0x04 |
| 11f4 | PUSH1 | 0x20 |
| 11f6 | MSTORE | |
| 11f7 | PUSH1 | 0x40 |
| 11f9 | DUP1 | |
| 11fa | PUSH0 | |
| 11fb | KECCAK256 | |
| 11fc | PUSH1 | 0x01 |
| 11fe | PUSH1 | 0x01 |
| 1200 | PUSH1 | 0x40 |
| 1202 | SHL | |
| 1203 | SUB | |
| 1204 | PUSH1 | 0x01 |
| 1206 | DUP3 | |
| 1207 | SLOAD | |
| 1208 | SWAP3 | |
| 1209 | ADD | |
| 120a | SLOAD | |
| 120b | AND | |
| 120c | DUP3 | |
| 120d | MLOAD | |
| 120e | SWAP2 | |
| 120f | DUP3 | |
| 1210 | MSTORE | |
| 1211 | PUSH1 | 0x20 |
| 1213 | DUP3 | |
| 1214 | ADD | |
| 1215 | MSTORE | |
| 1216 | RETURN | |
| 1217 | JUMPDEST | |
| 1218 | CALLVALUE | |
| 1219 | PUSH2 | 0x1189 |
| 121c | JUMPI | |
| 121d | PUSH0 | |
| 121e | CALLDATASIZE | |
| 121f | PUSH1 | 0x03 |
| 1221 | NOT | |
| 1222 | ADD | |
| 1223 | SLT | |
| 1224 | PUSH2 | 0x1189 |
| 1227 | JUMPI | |
| 1228 | PUSH1 | 0x40 |
| 122a | MLOAD | |
| 122b | PUSH32 | 0x000000000000000000000000a2e71fc2fb02d1ce93aa958e56cab83d26f3bfa6 |
| 124c | PUSH1 | 0x01 |
| 124e | PUSH1 | 0x01 |
| 1250 | PUSH1 | 0xa0 |
| 1252 | SHL | |
| 1253 | SUB | |
| 1254 | AND | |
| 1255 | DUP2 | |
| 1256 | MSTORE | |
| 1257 | PUSH1 | 0x20 |
| 1259 | SWAP1 | |
| 125a | RETURN | |
| 125b | JUMPDEST | |
| 125c | CALLVALUE | |
| 125d | PUSH2 | 0x1189 |
| 1260 | JUMPI | |
| 1261 | PUSH0 | |
| 1262 | CALLDATASIZE | |
| 1263 | PUSH1 | 0x03 |
| 1265 | NOT | |
| 1266 | ADD | |
| 1267 | SLT | |
| 1268 | PUSH2 | 0x1189 |
| 126b | JUMPI | |
| 126c | PUSH1 | 0x20 |
| 126e | PUSH1 | 0x40 |
| 1270 | MLOAD | |
| 1271 | PUSH32 | 0x08296c4851c7aca93c422c73902d61d179ed1bf52cf0ed257e6d096b9a8bb851 |
| 1292 | DUP2 | |
| 1293 | MSTORE | |
| 1294 | RETURN | |
| 1295 | JUMPDEST | |
| 1296 | CALLVALUE | |
| 1297 | PUSH2 | 0x1189 |
| 129a | JUMPI | |
| 129b | PUSH0 | |
| 129c | CALLDATASIZE | |
| 129d | PUSH1 | 0x03 |
| 129f | NOT | |
| 12a0 | ADD | |
| 12a1 | SLT | |
| 12a2 | PUSH2 | 0x1189 |
| 12a5 | JUMPI | |
| 12a6 | PUSH1 | 0x20 |
| 12a8 | PUSH1 | 0x05 |
| 12aa | SLOAD | |
| 12ab | PUSH1 | 0x40 |
| 12ad | MLOAD | |
| 12ae | SWAP1 | |
| 12af | DUP2 | |
| 12b0 | MSTORE | |
| 12b1 | RETURN | |
| 12b2 | JUMPDEST | |
| 12b3 | CALLVALUE | |
| 12b4 | PUSH2 | 0x1189 |
| 12b7 | JUMPI | |
| 12b8 | PUSH0 | |
| 12b9 | CALLDATASIZE | |
| 12ba | PUSH1 | 0x03 |
| 12bc | NOT | |
| 12bd | ADD | |
| 12be | SLT | |
| 12bf | PUSH2 | 0x1189 |
| 12c2 | JUMPI | |
| 12c3 | PUSH1 | 0x20 |
| 12c5 | PUSH1 | 0x02 |
| 12c7 | SLOAD | |
| 12c8 | PUSH1 | 0x40 |
| 12ca | MLOAD | |
| 12cb | SWAP1 | |
| 12cc | DUP2 | |
| 12cd | MSTORE | |
| 12ce | RETURN | |
| 12cf | JUMPDEST | |
| 12d0 | CALLVALUE | |
| 12d1 | PUSH2 | 0x1189 |
| 12d4 | JUMPI | |
| 12d5 | PUSH0 | |
| 12d6 | CALLDATASIZE | |
| 12d7 | PUSH1 | 0x03 |
| 12d9 | NOT | |
| 12da | ADD | |
| 12db | SLT | |
| 12dc | PUSH2 | 0x1189 |
| 12df | JUMPI | |
| 12e0 | PUSH0 | |
| 12e1 | SLOAD | |
| 12e2 | PUSH1 | 0x01 |
| 12e4 | PUSH1 | 0x01 |
| 12e6 | PUSH1 | 0xa0 |
| 12e8 | SHL | |
| 12e9 | SUB | |
| 12ea | DUP2 | |
| 12eb | AND | |
| 12ec | CALLER | |
| 12ed | SUB | |
| 12ee | PUSH2 | 0x132a |
| 12f1 | JUMPI | |
| 12f2 | PUSH12 | 0xffffffffffffffffffffffff |
| 12ff | PUSH1 | 0xa0 |
| 1301 | SHL | |
| 1302 | AND | |
| 1303 | PUSH0 | |
| 1304 | SSTORE | |
| 1305 | PUSH32 | 0x1b2d71eb44f882534bf4e86f940c56ccc869ffb927e2bab86561de93950c2216 |
| 1326 | PUSH0 | |
| 1327 | DUP1 | |
| 1328 | LOG1 | |
| 1329 | STOP | |
| 132a | JUMPDEST | |
| 132b | PUSH4 | 0x0bd42121 |
| 1330 | PUSH1 | 0xe1 |
| 1332 | SHL | |
| 1333 | PUSH0 | |
| 1334 | MSTORE | |
| 1335 | CALLER | |
| 1336 | PUSH1 | 0x04 |
| 1338 | MSTORE | |
| 1339 | PUSH1 | 0x24 |
| 133b | PUSH0 | |
| 133c | REVERT | |
| 133d | JUMPDEST | |
| 133e | CALLVALUE | |
| 133f | PUSH2 | 0x1189 |
| 1342 | JUMPI | |
| 1343 | PUSH1 | 0xa0 |
| 1345 | CALLDATASIZE | |
| 1346 | PUSH1 | 0x03 |
| 1348 | NOT | |
| 1349 | ADD | |
| 134a | SLT | |
| 134b | PUSH2 | 0x1189 |
| 134e | JUMPI | |
| 134f | PUSH1 | 0x04 |
| 1351 | CALLDATALOAD | |
| 1352 | PUSH1 | 0x24 |
| 1354 | CALLDATALOAD | |
| 1355 | PUSH1 | 0x44 |
| 1357 | CALLDATALOAD | |
| 1358 | PUSH2 | 0x135f |
| 135b | PUSH2 | 0x15c4 |
| 135e | JUMP | |
| 135f | JUMPDEST | |
| 1360 | PUSH1 | 0x84 |
| 1362 | CALLDATALOAD | |
| 1363 | PUSH1 | 0x01 |
| 1365 | PUSH1 | 0x01 |
| 1367 | PUSH1 | 0x40 |
| 1369 | SHL | |
| 136a | SUB | |
| 136b | DUP2 | |
| 136c | GT | |
| 136d | PUSH2 | 0x1189 |
| 1370 | JUMPI | |
| 1371 | PUSH2 | 0x137e |
| 1374 | SWAP1 | |
| 1375 | CALLDATASIZE | |
| 1376 | SWAP1 | |
| 1377 | PUSH1 | 0x04 |
| 1379 | ADD | |
| 137a | PUSH2 | 0x15f0 |
| 137d | JUMP | |
| 137e | JUMPDEST | |
| 137f | SWAP1 | |
| 1380 | SWAP2 | |
| 1381 | PUSH1 | 0x02 |
| 1383 | SLOAD | |
| 1384 | DUP1 | |
| 1385 | ISZERO | |
| 1386 | PUSH2 | 0x157f |
| 1389 | JUMPI | |
| 138a | DUP6 | |
| 138b | ISZERO | |
| 138c | PUSH2 | 0x1570 |
| 138f | JUMPI | |
| 1390 | DUP7 | |
| 1391 | PUSH0 | |
| 1392 | MSTORE | |
| 1393 | PUSH1 | 0x07 |
| 1395 | PUSH1 | 0x20 |
| 1397 | MSTORE | |
| 1398 | PUSH1 | 0x40 |
| 139a | PUSH0 | |
| 139b | KECCAK256 | |
| 139c | DUP6 | |
| 139d | PUSH0 | |
| 139e | MSTORE | |
| 139f | PUSH1 | 0x20 |
| 13a1 | MSTORE | |
| 13a2 | PUSH1 | 0xff |
| 13a4 | PUSH1 | 0x40 |
| 13a6 | PUSH0 | |
| 13a7 | KECCAK256 | |
| 13a8 | SLOAD | |
| 13a9 | AND | |
| 13aa | PUSH2 | 0x1559 |
| 13ad | JUMPI | |
| 13ae | DUP7 | |
| 13af | PUSH0 | |
| 13b0 | MSTORE | |
| 13b1 | PUSH1 | 0x04 |
| 13b3 | PUSH1 | 0x20 |
| 13b5 | MSTORE | |
| 13b6 | PUSH1 | 0x40 |
| 13b8 | PUSH0 | |
| 13b9 | KECCAK256 | |
| 13ba | SWAP4 | |
| 13bb | DUP5 | |
| 13bc | SLOAD | |
| 13bd | DUP1 | |
| 13be | DUP9 | |
| 13bf | GT | |
| 13c0 | PUSH2 | 0x153f |
| 13c3 | JUMPI | |
| 13c4 | POP | |
| 13c5 | PUSH2 | 0x14b0 |
| 13c8 | DUP9 | |
| 13c9 | PUSH2 | 0x14aa |
| 13cc | PUSH32 | 0x3ef380598f06b01333350e61cefa066c10a2088a64ad65aadd22eda04b972b89 |
| 13ed | SWAP10 | |
| 13ee | SWAP8 | |
| 13ef | SWAP6 | |
| 13f0 | PUSH1 | 0x80 |
| 13f2 | SWAP10 | |
| 13f3 | SWAP8 | |
| 13f4 | SWAP6 | |
| 13f5 | PUSH1 | 0x01 |
| 13f7 | PUSH1 | 0x01 |
| 13f9 | PUSH1 | 0x40 |
| 13fb | SHL | |
| 13fc | SUB | |
| 13fd | SWAP6 | |
| 13fe | PUSH1 | 0x06 |
| 1400 | SLOAD | |
| 1401 | SWAP8 | |
| 1402 | DUP8 | |
| 1403 | DUP10 | |
| 1404 | AND | |
| 1405 | SWAP6 | |
| 1406 | PUSH1 | 0x40 |
| 1408 | MLOAD | |
| 1409 | PUSH1 | 0x20 |
| 140b | DUP2 | |
| 140c | ADD | |
| 140d | SWAP2 | |
| 140e | DUP9 | |
| 140f | DUP4 | |
| 1410 | MSTORE | |
| 1411 | PUSH1 | 0x40 |
| 1413 | DUP3 | |
| 1414 | ADD | |
| 1415 | MSTORE | |
| 1416 | DUP14 | |
| 1417 | PUSH1 | 0x60 |
| 1419 | DUP3 | |
| 141a | ADD | |
| 141b | MSTORE | |
| 141c | DUP13 | |
| 141d | DUP16 | |
| 141e | DUP3 | |
| 141f | ADD | |
| 1420 | MSTORE | |
| 1421 | DUP15 | |
| 1422 | DUP2 | |
| 1423 | MSTORE | |
| 1424 | PUSH2 | 0x142e |
| 1427 | PUSH1 | 0xa0 |
| 1429 | DUP3 | |
| 142a | PUSH2 | 0x1620 |
| 142d | JUMP | |
| 142e | JUMPDEST | |
| 142f | MLOAD | |
| 1430 | SWAP1 | |
| 1431 | KECCAK256 | |
| 1432 | PUSH1 | 0x40 |
| 1434 | MLOAD | |
| 1435 | PUSH1 | 0x20 |
| 1437 | DUP2 | |
| 1438 | ADD | |
| 1439 | SWAP2 | |
| 143a | PUSH32 | 0xd850f5df47b124511e8e6ec99cf1a0beaf7c6237eff0a31305ce53d85f312675 |
| 145b | DUP4 | |
| 145c | MSTORE | |
| 145d | CHAINID | |
| 145e | PUSH1 | 0x40 |
| 1460 | DUP4 | |
| 1461 | ADD | |
| 1462 | MSTORE | |
| 1463 | ADDRESS | |
| 1464 | PUSH1 | 0x60 |
| 1466 | DUP4 | |
| 1467 | ADD | |
| 1468 | MSTORE | |
| 1469 | DUP16 | |
| 146a | PUSH32 | 0x07e27cdd90594a3caa105e64724b3ff44d247017420d1a3df2cc49fa10cdf0f5 |
| 148b | SWAP1 | |
| 148c | DUP4 | |
| 148d | ADD | |
| 148e | MSTORE | |
| 148f | DUP11 | |
| 1490 | DUP8 | |
| 1491 | AND | |
| 1492 | PUSH1 | 0xa0 |
| 1494 | DUP4 | |
| 1495 | ADD | |
| 1496 | MSTORE | |
| 1497 | PUSH1 | 0xc0 |
| 1499 | DUP3 | |
| 149a | ADD | |
| 149b | MSTORE | |
| 149c | PUSH1 | 0xc0 |
| 149e | DUP2 | |
| 149f | MSTORE | |
| 14a0 | PUSH2 | 0x02c1 |
| 14a3 | PUSH1 | 0xe0 |
| 14a5 | DUP3 | |
| 14a6 | PUSH2 | 0x1620 |
| 14a9 | JUMP | |
| 14aa | JUMPDEST | |
| 14ab | POP | |
| 14ac | PUSH2 | 0x1655 |
| 14af | JUMP | |
| 14b0 | JUMPDEST | |
| 14b1 | AND | |
| 14b2 | SWAP1 | |
| 14b3 | PUSH1 | 0x01 |
| 14b5 | PUSH1 | 0x01 |
| 14b7 | PUSH1 | 0x40 |
| 14b9 | SHL | |
| 14ba | SUB | |
| 14bb | NOT | |
| 14bc | AND | |
| 14bd | OR | |
| 14be | PUSH1 | 0x06 |
| 14c0 | SSTORE | |
| 14c1 | DUP6 | |
| 14c2 | PUSH0 | |
| 14c3 | MSTORE | |
| 14c4 | PUSH1 | 0x07 |
| 14c6 | PUSH1 | 0x20 |
| 14c8 | MSTORE | |
| 14c9 | PUSH1 | 0x40 |
| 14cb | PUSH0 | |
| 14cc | KECCAK256 | |
| 14cd | DUP3 | |
| 14ce | PUSH0 | |
| 14cf | MSTORE | |
| 14d0 | PUSH1 | 0x20 |
| 14d2 | MSTORE | |
| 14d3 | PUSH1 | 0x40 |
| 14d5 | PUSH0 | |
| 14d6 | KECCAK256 | |
| 14d7 | PUSH1 | 0x01 |
| 14d9 | PUSH1 | 0xff |
| 14db | NOT | |
| 14dc | DUP3 | |
| 14dd | SLOAD | |
| 14de | AND | |
| 14df | OR | |
| 14e0 | SWAP1 | |
| 14e1 | SSTORE | |
| 14e2 | DUP3 | |
| 14e3 | DUP2 | |
| 14e4 | SLOAD | |
| 14e5 | SUB | |
| 14e6 | DUP2 | |
| 14e7 | SSTORE | |
| 14e8 | DUP3 | |
| 14e9 | PUSH1 | 0x05 |
| 14eb | SLOAD | |
| 14ec | SUB | |
| 14ed | PUSH1 | 0x05 |
| 14ef | SSTORE | |
| 14f0 | DUP3 | |
| 14f1 | PUSH1 | 0x03 |
| 14f3 | SLOAD | |
| 14f4 | ADD | |
| 14f5 | PUSH1 | 0x03 |
| 14f7 | SSTORE | |
| 14f8 | PUSH1 | 0x01 |
| 14fa | PUSH1 | 0x01 |
| 14fc | PUSH1 | 0x40 |
| 14fe | SHL | |
| 14ff | SUB | |
| 1500 | PUSH1 | 0x01 |
| 1502 | DUP3 | |
| 1503 | ADD | |
| 1504 | SWAP2 | |
| 1505 | DUP2 | |
| 1506 | PUSH2 | 0x1511 |
| 1509 | DUP2 | |
| 150a | DUP6 | |
| 150b | SLOAD | |
| 150c | AND | |
| 150d | PUSH2 | 0x1655 |
| 1510 | JUMP | |
| 1511 | JUMPDEST | |
| 1512 | AND | |
| 1513 | DUP3 | |
| 1514 | NOT | |
| 1515 | DUP5 | |
| 1516 | SLOAD | |
| 1517 | AND | |
| 1518 | OR | |
| 1519 | DUP4 | |
| 151a | SSTORE | |
| 151b | PUSH2 | 0x1522 |
| 151e | PUSH2 | 0x19fa |
| 1521 | JUMP | |
| 1522 | JUMPDEST | |
| 1523 | SLOAD | |
| 1524 | SWAP2 | |
| 1525 | SLOAD | |
| 1526 | AND | |
| 1527 | SWAP1 | |
| 1528 | PUSH1 | 0x40 |
| 152a | MLOAD | |
| 152b | SWAP4 | |
| 152c | DUP5 | |
| 152d | MSTORE | |
| 152e | PUSH1 | 0x20 |
| 1530 | DUP5 | |
| 1531 | ADD | |
| 1532 | MSTORE | |
| 1533 | PUSH1 | 0x40 |
| 1535 | DUP4 | |
| 1536 | ADD | |
| 1537 | MSTORE | |
| 1538 | PUSH1 | 0x60 |
| 153a | DUP3 | |
| 153b | ADD | |
| 153c | MSTORE | |
| 153d | LOG2 | |
| 153e | STOP | |
| 153f | JUMPDEST | |
| 1540 | DUP8 | |
| 1541 | DUP10 | |
| 1542 | PUSH4 | 0x7c06acb7 |
| 1547 | PUSH1 | 0xe1 |
| 1549 | SHL | |
| 154a | PUSH0 | |
| 154b | MSTORE | |
| 154c | PUSH1 | 0x04 |
| 154e | MSTORE | |
| 154f | PUSH1 | 0x24 |
| 1551 | MSTORE | |
| 1552 | PUSH1 | 0x44 |
| 1554 | MSTORE | |
| 1555 | PUSH1 | 0x64 |
| 1557 | PUSH0 | |
| 1558 | REVERT | |
| 1559 | JUMPDEST | |
| 155a | DUP5 | |
| 155b | DUP8 | |
| 155c | PUSH4 | 0x0dd4fdfd |
| 1561 | PUSH1 | 0xe2 |
| 1563 | SHL | |
| 1564 | PUSH0 | |
| 1565 | MSTORE | |
| 1566 | PUSH1 | 0x04 |
| 1568 | MSTORE | |
| 1569 | PUSH1 | 0x24 |
| 156b | MSTORE | |
| 156c | PUSH1 | 0x44 |
| 156e | PUSH0 | |
| 156f | REVERT | |
| 1570 | JUMPDEST | |
| 1571 | PUSH4 | 0x1f2a2005 |
| 1576 | PUSH1 | 0xe0 |
| 1578 | SHL | |
| 1579 | PUSH0 | |
| 157a | MSTORE | |
| 157b | PUSH1 | 0x04 |
| 157d | PUSH0 | |
| 157e | REVERT | |
| 157f | JUMPDEST | |
| 1580 | PUSH4 | 0xd311bc39 |
| 1585 | PUSH1 | 0xe0 |
| 1587 | SHL | |
| 1588 | PUSH0 | |
| 1589 | MSTORE | |
| 158a | PUSH1 | 0x04 |
| 158c | PUSH0 | |
| 158d | REVERT | |
| 158e | JUMPDEST | |
| 158f | CALLVALUE | |
| 1590 | PUSH2 | 0x1189 |
| 1593 | JUMPI | |
| 1594 | PUSH1 | 0x40 |
| 1596 | CALLDATASIZE | |
| 1597 | PUSH1 | 0x03 |
| 1599 | NOT | |
| 159a | ADD | |
| 159b | SLT | |
| 159c | PUSH2 | 0x1189 |
| 159f | JUMPI | |
| 15a0 | PUSH1 | 0x20 |
| 15a2 | SWAP1 | |
| 15a3 | PUSH1 | 0x04 |
| 15a5 | CALLDATALOAD | |
| 15a6 | PUSH0 | |
| 15a7 | MSTORE | |
| 15a8 | PUSH1 | 0x07 |
| 15aa | DUP3 | |
| 15ab | MSTORE | |
| 15ac | PUSH1 | 0x40 |
| 15ae | PUSH0 | |
| 15af | KECCAK256 | |
| 15b0 | PUSH1 | 0x24 |
| 15b2 | CALLDATALOAD | |
| 15b3 | PUSH0 | |
| 15b4 | MSTORE | |
| 15b5 | DUP3 | |
| 15b6 | MSTORE | |
| 15b7 | PUSH1 | 0xff |
| 15b9 | PUSH1 | 0x40 |
| 15bb | PUSH0 | |
| 15bc | KECCAK256 | |
| 15bd | SLOAD | |
| 15be | AND | |
| 15bf | ISZERO | |
| 15c0 | ISZERO | |
| 15c1 | DUP2 | |
| 15c2 | MSTORE | |
| 15c3 | RETURN | |
| 15c4 | JUMPDEST | |
| 15c5 | PUSH1 | 0x64 |
| 15c7 | CALLDATALOAD | |
| 15c8 | SWAP1 | |
| 15c9 | PUSH1 | 0x01 |
| 15cb | PUSH1 | 0x01 |
| 15cd | PUSH1 | 0x40 |
| 15cf | SHL | |
| 15d0 | SUB | |
| 15d1 | DUP3 | |
| 15d2 | AND | |
| 15d3 | DUP3 | |
| 15d4 | SUB | |
| 15d5 | PUSH2 | 0x1189 |
| 15d8 | JUMPI | |
| 15d9 | JUMP | |
| 15da | JUMPDEST | |
| 15db | PUSH1 | 0x44 |
| 15dd | CALLDATALOAD | |
| 15de | SWAP1 | |
| 15df | PUSH1 | 0x01 |
| 15e1 | PUSH1 | 0x01 |
| 15e3 | PUSH1 | 0x40 |
| 15e5 | SHL | |
| 15e6 | SUB | |
| 15e7 | DUP3 | |
| 15e8 | AND | |
| 15e9 | DUP3 | |
| 15ea | SUB | |
| 15eb | PUSH2 | 0x1189 |
| 15ee | JUMPI | |
| 15ef | JUMP | |
| 15f0 | JUMPDEST | |
| 15f1 | SWAP2 | |
| 15f2 | DUP2 | |
| 15f3 | PUSH1 | 0x1f |
| 15f5 | DUP5 | |
| 15f6 | ADD | |
| 15f7 | SLT | |
| 15f8 | ISZERO | |
| 15f9 | PUSH2 | 0x1189 |
| 15fc | JUMPI | |
| 15fd | DUP3 | |
| 15fe | CALLDATALOAD | |
| 15ff | SWAP2 | |
| 1600 | PUSH1 | 0x01 |
| 1602 | PUSH1 | 0x01 |
| 1604 | PUSH1 | 0x40 |
| 1606 | SHL | |
| 1607 | SUB | |
| 1608 | DUP4 | |
| 1609 | GT | |
| 160a | PUSH2 | 0x1189 |
| 160d | JUMPI | |
| 160e | PUSH1 | 0x20 |
| 1610 | DUP1 | |
| 1611 | DUP6 | |
| 1612 | ADD | |
| 1613 | SWAP5 | |
| 1614 | DUP5 | |
| 1615 | PUSH1 | 0x05 |
| 1617 | SHL | |
| 1618 | ADD | |
| 1619 | ADD | |
| 161a | GT | |
| 161b | PUSH2 | 0x1189 |
| 161e | JUMPI | |
| 161f | JUMP | |
| 1620 | JUMPDEST | |
| 1621 | SWAP1 | |
| 1622 | PUSH1 | 0x1f |
| 1624 | DUP1 | |
| 1625 | NOT | |
| 1626 | SWAP2 | |
| 1627 | ADD | |
| 1628 | AND | |
| 1629 | DUP2 | |
| 162a | ADD | |
| 162b | SWAP1 | |
| 162c | DUP2 | |
| 162d | LT | |
| 162e | PUSH1 | 0x01 |
| 1630 | PUSH1 | 0x01 |
| 1632 | PUSH1 | 0x40 |
| 1634 | SHL | |
| 1635 | SUB | |
| 1636 | DUP3 | |
| 1637 | GT | |
| 1638 | OR | |
| 1639 | PUSH2 | 0x1641 |
| 163c | JUMPI | |
| 163d | PUSH1 | 0x40 |
| 163f | MSTORE | |
| 1640 | JUMP | |
| 1641 | JUMPDEST | |
| 1642 | PUSH4 | 0x4e487b71 |
| 1647 | PUSH1 | 0xe0 |
| 1649 | SHL | |
| 164a | PUSH0 | |
| 164b | MSTORE | |
| 164c | PUSH1 | 0x41 |
| 164e | PUSH1 | 0x04 |
| 1650 | MSTORE | |
| 1651 | PUSH1 | 0x24 |
| 1653 | PUSH0 | |
| 1654 | REVERT | |
| 1655 | JUMPDEST | |
| 1656 | PUSH1 | 0x01 |
| 1658 | PUSH1 | 0x01 |
| 165a | PUSH1 | 0x40 |
| 165c | SHL | |
| 165d | SUB | |
| 165e | PUSH1 | 0x01 |
| 1660 | SWAP2 | |
| 1661 | AND | |
| 1662 | ADD | |
| 1663 | SWAP1 | |
| 1664 | PUSH1 | 0x01 |
| 1666 | PUSH1 | 0x01 |
| 1668 | PUSH1 | 0x40 |
| 166a | SHL | |
| 166b | SUB | |
| 166c | DUP3 | |
| 166d | GT | |
| 166e | PUSH2 | 0x1673 |
| 1671 | JUMPI | |
| 1672 | JUMP | |
| 1673 | JUMPDEST | |
| 1674 | PUSH4 | 0x4e487b71 |
| 1679 | PUSH1 | 0xe0 |
| 167b | SHL | |
| 167c | PUSH0 | |
| 167d | MSTORE | |
| 167e | PUSH1 | 0x11 |
| 1680 | PUSH1 | 0x04 |
| 1682 | MSTORE | |
| 1683 | PUSH1 | 0x24 |
| 1685 | PUSH0 | |
| 1686 | REVERT | |
| 1687 | JUMPDEST | |
| 1688 | SWAP2 | |
| 1689 | SWAP1 | |
| 168a | DUP3 | |
| 168b | ADD | |
| 168c | DUP1 | |
| 168d | SWAP3 | |
| 168e | GT | |
| 168f | PUSH2 | 0x1673 |
| 1692 | JUMPI | |
| 1693 | JUMP | |
| 1694 | JUMPDEST | |
| 1695 | SWAP1 | |
| 1696 | CALLDATALOAD | |
| 1697 | PUSH1 | 0x1e |
| 1699 | NOT | |
| 169a | DUP3 | |
| 169b | CALLDATASIZE | |
| 169c | SUB | |
| 169d | ADD | |
| 169e | DUP2 | |
| 169f | SLT | |
| 16a0 | ISZERO | |
| 16a1 | PUSH2 | 0x1189 |
| 16a4 | JUMPI | |
| 16a5 | ADD | |
| 16a6 | PUSH1 | 0x20 |
| 16a8 | DUP2 | |
| 16a9 | CALLDATALOAD | |
| 16aa | SWAP2 | |
| 16ab | ADD | |
| 16ac | SWAP2 | |
| 16ad | PUSH1 | 0x01 |
| 16af | PUSH1 | 0x01 |
| 16b1 | PUSH1 | 0x40 |
| 16b3 | SHL | |
| 16b4 | SUB | |
| 16b5 | DUP3 | |
| 16b6 | GT | |
| 16b7 | PUSH2 | 0x1189 |
| 16ba | JUMPI | |
| 16bb | DUP2 | |
| 16bc | CALLDATASIZE | |
| 16bd | SUB | |
| 16be | DUP4 | |
| 16bf | SGT | |
| 16c0 | PUSH2 | 0x1189 |
| 16c3 | JUMPI | |
| 16c4 | JUMP | |
| 16c5 | JUMPDEST | |
| 16c6 | SWAP1 | |
| 16c7 | DUP1 | |
| 16c8 | PUSH1 | 0x20 |
| 16ca | SWAP4 | |
| 16cb | SWAP3 | |
| 16cc | DUP2 | |
| 16cd | DUP5 | |
| 16ce | MSTORE | |
| 16cf | DUP5 | |
| 16d0 | DUP5 | |
| 16d1 | ADD | |
| 16d2 | CALLDATACOPY | |
| 16d3 | PUSH0 | |
| 16d4 | DUP3 | |
| 16d5 | DUP3 | |
| 16d6 | ADD | |
| 16d7 | DUP5 | |
| 16d8 | ADD | |
| 16d9 | MSTORE | |
| 16da | PUSH1 | 0x1f |
| 16dc | ADD | |
| 16dd | PUSH1 | 0x1f |
| 16df | NOT | |
| 16e0 | AND | |
| 16e1 | ADD | |
| 16e2 | ADD | |
| 16e3 | SWAP1 | |
| 16e4 | JUMP | |
| 16e5 | JUMPDEST | |
| 16e6 | SWAP1 | |
| 16e7 | DUP2 | |
| 16e8 | PUSH1 | 0x20 |
| 16ea | SWAP2 | |
| 16eb | SUB | |
| 16ec | SLT | |
| 16ed | PUSH2 | 0x1189 |
| 16f0 | JUMPI | |
| 16f1 | MLOAD | |
| 16f2 | DUP1 | |
| 16f3 | ISZERO | |
| 16f4 | ISZERO | |
| 16f5 | DUP2 | |
| 16f6 | SUB | |
| 16f7 | PUSH2 | 0x1189 |
| 16fa | JUMPI | |
| 16fb | SWAP1 | |
| 16fc | JUMP | |
| 16fd | JUMPDEST | |
| 16fe | DUP2 | |
| 16ff | DUP4 | |
| 1700 | MSTORE | |
| 1701 | SWAP1 | |
| 1702 | SWAP2 | |
| 1703 | PUSH1 | 0x01 |
| 1705 | PUSH1 | 0x01 |
| 1707 | PUSH1 | 0xfb |
| 1709 | SHL | |
| 170a | SUB | |
| 170b | DUP4 | |
| 170c | GT | |
| 170d | PUSH2 | 0x1189 |
| 1710 | JUMPI | |
| 1711 | PUSH1 | 0x20 |
| 1713 | SWAP3 | |
| 1714 | PUSH1 | 0x05 |
| 1716 | SHL | |
| 1717 | DUP1 | |
| 1718 | SWAP3 | |
| 1719 | DUP5 | |
| 171a | DUP4 | |
| 171b | ADD | |
| 171c | CALLDATACOPY | |
| 171d | ADD | |
| 171e | ADD | |
| 171f | SWAP1 | |
| 1720 | JUMP | |
| 1721 | JUMPDEST | |
| 1722 | SWAP2 | |
| 1723 | SWAP1 | |
| 1724 | DUP2 | |
| 1725 | LT | |
| 1726 | ISZERO | |
| 1727 | PUSH2 | 0x1731 |
| 172a | JUMPI | |
| 172b | PUSH1 | 0x05 |
| 172d | SHL | |
| 172e | ADD | |
| 172f | SWAP1 | |
| 1730 | JUMP | |
| 1731 | JUMPDEST | |
| 1732 | PUSH4 | 0x4e487b71 |
| 1737 | PUSH1 | 0xe0 |
| 1739 | SHL | |
| 173a | PUSH0 | |
| 173b | MSTORE | |
| 173c | PUSH1 | 0x32 |
| 173e | PUSH1 | 0x04 |
| 1740 | MSTORE | |
| 1741 | PUSH1 | 0x24 |
| 1743 | PUSH0 | |
| 1744 | REVERT | |
| 1745 | JUMPDEST | |
| 1746 | CALLDATALOAD | |
| 1747 | PUSH1 | 0x01 |
| 1749 | PUSH1 | 0x01 |
| 174b | PUSH1 | 0x40 |
| 174d | SHL | |
| 174e | SUB | |
| 174f | DUP2 | |
| 1750 | AND | |
| 1751 | DUP2 | |
| 1752 | SUB | |
| 1753 | PUSH2 | 0x1189 |
| 1756 | JUMPI | |
| 1757 | SWAP1 | |
| 1758 | JUMP | |
| 1759 | JUMPDEST | |
| 175a | SWAP2 | |
| 175b | SWAP1 | |
| 175c | DUP3 | |
| 175d | SUB | |
| 175e | SWAP2 | |
| 175f | DUP3 | |
| 1760 | GT | |
| 1761 | PUSH2 | 0x1673 |
| 1764 | JUMPI | |
| 1765 | JUMP | |
| 1766 | JUMPDEST | |
| 1767 | CALLDATALOAD | |
| 1768 | PUSH1 | 0x01 |
| 176a | PUSH1 | 0x01 |
| 176c | PUSH1 | 0xa0 |
| 176e | SHL | |
| 176f | SUB | |
| 1770 | DUP2 | |
| 1771 | AND | |
| 1772 | DUP2 | |
| 1773 | SUB | |
| 1774 | PUSH2 | 0x1189 |
| 1777 | JUMPI | |
| 1778 | SWAP1 | |
| 1779 | JUMP | |
| 177a | JUMPDEST | |
| 177b | CALLDATALOAD | |
| 177c | PUSH1 | 0xff |
| 177e | DUP2 | |
| 177f | AND | |
| 1780 | DUP2 | |
| 1781 | SUB | |
| 1782 | PUSH2 | 0x1189 |
| 1785 | JUMPI | |
| 1786 | SWAP1 | |
| 1787 | JUMP | |
| 1788 | JUMPDEST | |
| 1789 | SWAP5 | |
| 178a | SWAP4 | |
| 178b | SWAP2 | |
| 178c | SWAP6 | |
| 178d | SWAP7 | |
| 178e | PUSH0 | |
| 178f | SWAP8 | |
| 1790 | DUP6 | |
| 1791 | ISZERO | |
| 1792 | PUSH2 | 0x19eb |
| 1795 | JUMPI | |
| 1796 | PUSH1 | 0x01 |
| 1798 | PUSH1 | 0x01 |
| 179a | PUSH1 | 0x40 |
| 179c | SHL | |
| 179d | SUB | |
| 179e | AND | |
| 179f | NUMBER | |
| 17a0 | DUP2 | |
| 17a1 | GT | |
| 17a2 | PUSH2 | 0x19d5 |
| 17a5 | JUMPI | |
| 17a6 | PUSH2 | 0x0258 |
| 17a9 | PUSH2 | 0x17b2 |
| 17ac | DUP3 | |
| 17ad | NUMBER | |
| 17ae | PUSH2 | 0x1759 |
| 17b1 | JUMP | |
| 17b2 | JUMPDEST | |
| 17b3 | GT | |
| 17b4 | PUSH2 | 0x19bf |
| 17b7 | JUMPI | |
| 17b8 | POP | |
| 17b9 | PUSH1 | 0x40 |
| 17bb | MLOAD | |
| 17bc | SWAP4 | |
| 17bd | PUSH1 | 0x20 |
| 17bf | DUP6 | |
| 17c0 | ADD | |
| 17c1 | MSTORE | |
| 17c2 | PUSH1 | 0x20 |
| 17c4 | DUP5 | |
| 17c5 | MSTORE | |
| 17c6 | PUSH2 | 0x17d0 |
| 17c9 | PUSH1 | 0x40 |
| 17cb | DUP6 | |
| 17cc | PUSH2 | 0x1620 |
| 17cf | JUMP | |
| 17d0 | JUMPDEST | |
| 17d1 | PUSH0 | |
| 17d2 | SWAP5 | |
| 17d3 | PUSH0 | |
| 17d4 | SWAP9 | |
| 17d5 | JUMPDEST | |
| 17d6 | DUP9 | |
| 17d7 | DUP11 | |
| 17d8 | LT | |
| 17d9 | ISZERO | |
| 17da | PUSH2 | 0x1995 |
| 17dd | JUMPI | |
| 17de | DUP10 | |
| 17df | PUSH1 | 0x05 |
| 17e1 | SHL | |
| 17e2 | DUP5 | |
| 17e3 | ADD | |
| 17e4 | CALLDATALOAD | |
| 17e5 | PUSH1 | 0x7e |
| 17e7 | NOT | |
| 17e8 | DUP6 | |
| 17e9 | CALLDATASIZE | |
| 17ea | SUB | |
| 17eb | ADD | |
| 17ec | DUP2 | |
| 17ed | SLT | |
| 17ee | ISZERO | |
| 17ef | PUSH2 | 0x1189 |
| 17f2 | JUMPI | |
| 17f3 | DUP5 | |
| 17f4 | ADD | |
| 17f5 | SWAP7 | |
| 17f6 | PUSH2 | 0x17fe |
| 17f9 | DUP9 | |
| 17fa | PUSH2 | 0x1766 |
| 17fd | JUMP | |
| 17fe | JUMPDEST | |
| 17ff | PUSH1 | 0x01 |
| 1801 | PUSH1 | 0x01 |
| 1803 | PUSH1 | 0xa0 |
| 1805 | SHL | |
| 1806 | SUB | |
| 1807 | SWAP2 | |
| 1808 | DUP3 | |
| 1809 | AND | |
| 180a | SWAP2 | |
| 180b | AND | |
| 180c | DUP2 | |
| 180d | LT | |
| 180e | ISZERO | |
| 180f | PUSH2 | 0x1969 |
| 1812 | JUMPI | |
| 1813 | POP | |
| 1814 | PUSH2 | 0x181c |
| 1817 | DUP8 | |
| 1818 | PUSH2 | 0x1766 |
| 181b | JUMP | |
| 181c | JUMPDEST | |
| 181d | SWAP7 | |
| 181e | PUSH2 | 0x185d |
| 1821 | PUSH1 | 0x20 |
| 1823 | DUP8 | |
| 1824 | PUSH2 | 0x182c |
| 1827 | DUP5 | |
| 1828 | PUSH2 | 0x1766 |
| 182b | JUMP | |
| 182c | JUMPDEST | |
| 182d | PUSH1 | 0x40 |
| 182f | MLOAD | |
| 1830 | PUSH4 | 0x2e4bfa51 |
| 1835 | PUSH1 | 0xe1 |
| 1837 | SHL | |
| 1838 | DUP2 | |
| 1839 | MSTORE | |
| 183a | PUSH1 | 0x01 |
| 183c | PUSH1 | 0x01 |
| 183e | PUSH1 | 0xa0 |
| 1840 | SHL | |
| 1841 | SUB | |
| 1842 | SWAP1 | |
| 1843 | SWAP2 | |
| 1844 | AND | |
| 1845 | PUSH1 | 0x04 |
| 1847 | DUP3 | |
| 1848 | ADD | |
| 1849 | MSTORE | |
| 184a | PUSH1 | 0x24 |
| 184c | DUP2 | |
| 184d | ADD | |
| 184e | SWAP2 | |
| 184f | SWAP1 | |
| 1850 | SWAP2 | |
| 1851 | MSTORE | |
| 1852 | SWAP2 | |
| 1853 | DUP3 | |
| 1854 | SWAP1 | |
| 1855 | DUP2 | |
| 1856 | SWAP1 | |
| 1857 | PUSH1 | 0x44 |
| 1859 | DUP3 | |
| 185a | ADD | |
| 185b | SWAP1 | |
| 185c | JUMP | |
| 185d | JUMPDEST | |
| 185e | SUB | |
| 185f | DUP2 | |
| 1860 | PUSH1 | 0x01 |
| 1862 | PUSH1 | 0x01 |
| 1864 | PUSH1 | 0xa0 |
| 1866 | SHL | |
| 1867 | SUB | |
| 1868 | DUP15 | |
| 1869 | AND | |
| 186a | GAS | |
| 186b | STATICCALL | |
| 186c | SWAP1 | |
| 186d | DUP2 | |
| 186e | ISZERO | |
| 186f | PUSH2 | 0x1104 |
| 1872 | JUMPI | |
| 1873 | PUSH0 | |
| 1874 | SWAP2 | |
| 1875 | PUSH2 | 0x194b |
| 1878 | JUMPI | |
| 1879 | JUMPDEST | |
| 187a | POP | |
| 187b | ISZERO | |
| 187c | PUSH2 | 0x1924 |
| 187f | JUMPI | |
| 1880 | PUSH1 | 0x20 |
| 1882 | DUP2 | |
| 1883 | ADD | |
| 1884 | SWAP1 | |
| 1885 | PUSH1 | 0x04 |
| 1887 | PUSH1 | 0xff |
| 1889 | PUSH2 | 0x1891 |
| 188c | DUP5 | |
| 188d | PUSH2 | 0x177a |
| 1890 | JUMP | |
| 1891 | JUMPDEST | |
| 1892 | AND | |
| 1893 | SUB | |
| 1894 | PUSH2 | 0x18f1 |
| 1897 | JUMPI | |
| 1898 | PUSH2 | 0x18a2 |
| 189b | DUP9 | |
| 189c | DUP3 | |
| 189d | DUP13 | |
| 189e | PUSH2 | 0x1b1a |
| 18a1 | JUMP | |
| 18a2 | JUMPDEST | |
| 18a3 | ISZERO | |
| 18a4 | PUSH2 | 0x18bd |
| 18a7 | JUMPI | |
| 18a8 | POP | |
| 18a9 | POP | |
| 18aa | PUSH0 | |
| 18ab | NOT | |
| 18ac | DUP2 | |
| 18ad | EQ | |
| 18ae | PUSH2 | 0x1673 |
| 18b1 | JUMPI | |
| 18b2 | PUSH1 | 0x01 |
| 18b4 | SWAP10 | |
| 18b5 | DUP11 | |
| 18b6 | ADD | |
| 18b7 | SWAP10 | |
| 18b8 | ADD | |
| 18b9 | PUSH2 | 0x17d5 |
| 18bc | JUMP | |
| 18bd | JUMPDEST | |
| 18be | SWAP1 | |
| 18bf | PUSH2 | 0x18d2 |
| 18c2 | PUSH2 | 0x18cc |
| 18c5 | PUSH1 | 0xff |
| 18c7 | SWAP4 | |
| 18c8 | PUSH2 | 0x1766 |
| 18cb | JUMP | |
| 18cc | JUMPDEST | |
| 18cd | SWAP2 | |
| 18ce | PUSH2 | 0x177a |
| 18d1 | JUMP | |
| 18d2 | JUMPDEST | |
| 18d3 | SWAP1 | |
| 18d4 | PUSH4 | 0xbbf82ba3 |
| 18d9 | PUSH1 | 0xe0 |
| 18db | SHL | |
| 18dc | PUSH0 | |
| 18dd | MSTORE | |
| 18de | PUSH1 | 0x01 |
| 18e0 | DUP1 | |
| 18e1 | PUSH1 | 0xa0 |
| 18e3 | SHL | |
| 18e4 | SUB | |
| 18e5 | AND | |
| 18e6 | PUSH1 | 0x04 |
| 18e8 | MSTORE | |
| 18e9 | AND | |
| 18ea | PUSH1 | 0x24 |
| 18ec | MSTORE | |
| 18ed | PUSH1 | 0x44 |
| 18ef | PUSH0 | |
| 18f0 | REVERT | |
| 18f1 | JUMPDEST | |
| 18f2 | SWAP1 | |
| 18f3 | PUSH2 | 0x1900 |
| 18f6 | PUSH2 | 0x18cc |
| 18f9 | PUSH1 | 0xff |
| 18fb | SWAP4 | |
| 18fc | PUSH2 | 0x1766 |
| 18ff | JUMP | |
| 1900 | JUMPDEST | |
| 1901 | SWAP1 | |
| 1902 | PUSH4 | 0x587548c3 |
| 1907 | PUSH1 | 0xe1 |
| 1909 | SHL | |
| 190a | PUSH0 | |
| 190b | MSTORE | |
| 190c | PUSH1 | 0x01 |
| 190e | DUP1 | |
| 190f | PUSH1 | 0xa0 |
| 1911 | SHL | |
| 1912 | SUB | |
| 1913 | AND | |
| 1914 | PUSH1 | 0x04 |
| 1916 | MSTORE | |
| 1917 | AND | |
| 1918 | PUSH1 | 0x24 |
| 191a | MSTORE | |
| 191b | PUSH1 | 0x04 |
| 191d | PUSH1 | 0x44 |
| 191f | MSTORE | |
| 1920 | PUSH1 | 0x64 |
| 1922 | PUSH0 | |
| 1923 | REVERT | |
| 1924 | JUMPDEST | |
| 1925 | PUSH2 | 0x192e |
| 1928 | DUP7 | |
| 1929 | SWAP2 | |
| 192a | PUSH2 | 0x1766 |
| 192d | JUMP | |
| 192e | JUMPDEST | |
| 192f | PUSH4 | 0xae8bb039 |
| 1934 | PUSH1 | 0xe0 |
| 1936 | SHL | |
| 1937 | PUSH0 | |
| 1938 | MSTORE | |
| 1939 | PUSH1 | 0x01 |
| 193b | DUP1 | |
| 193c | PUSH1 | 0xa0 |
| 193e | SHL | |
| 193f | SUB | |
| 1940 | AND | |
| 1941 | PUSH1 | 0x04 |
| 1943 | MSTORE | |
| 1944 | PUSH1 | 0x24 |
| 1946 | MSTORE | |
| 1947 | PUSH1 | 0x44 |
| 1949 | PUSH0 | |
| 194a | REVERT | |
| 194b | JUMPDEST | |
| 194c | PUSH2 | 0x1963 |
| 194f | SWAP2 | |
| 1950 | POP | |
| 1951 | PUSH1 | 0x20 |
| 1953 | RETURNDATASIZE | |
| 1954 | DUP2 | |
| 1955 | GT | |
| 1956 | PUSH2 | 0x0ea4 |
| 1959 | JUMPI | |
| 195a | PUSH2 | 0x0e96 |
| 195d | DUP2 | |
| 195e | DUP4 | |
| 195f | PUSH2 | 0x1620 |
| 1962 | JUMP | |
| 1963 | JUMPDEST | |
| 1964 | PUSH0 | |
| 1965 | PUSH2 | 0x1879 |
| 1968 | JUMP | |
| 1969 | JUMPDEST | |
| 196a | PUSH2 | 0x1972 |
| 196d | DUP9 | |
| 196e | PUSH2 | 0x1766 |
| 1971 | JUMP | |
| 1972 | JUMPDEST | |
| 1973 | PUSH4 | 0x11641feb |
| 1978 | PUSH1 | 0xe2 |
| 197a | SHL | |
| 197b | PUSH0 | |
| 197c | SWAP1 | |
| 197d | DUP2 | |
| 197e | MSTORE | |
| 197f | PUSH1 | 0x04 |
| 1981 | SWAP3 | |
| 1982 | SWAP1 | |
| 1983 | SWAP3 | |
| 1984 | MSTORE | |
| 1985 | PUSH1 | 0x01 |
| 1987 | PUSH1 | 0x01 |
| 1989 | PUSH1 | 0xa0 |
| 198b | SHL | |
| 198c | SUB | |
| 198d | AND | |
| 198e | PUSH1 | 0x24 |
| 1990 | MSTORE | |
| 1991 | PUSH1 | 0x44 |
| 1993 | SWAP1 | |
| 1994 | REVERT | |
| 1995 | JUMPDEST | |
| 1996 | SWAP9 | |
| 1997 | POP | |
| 1998 | SWAP6 | |
| 1999 | POP | |
| 199a | SWAP6 | |
| 199b | POP | |
| 199c | POP | |
| 199d | POP | |
| 199e | POP | |
| 199f | POP | |
| 19a0 | DUP1 | |
| 19a1 | DUP4 | |
| 19a2 | LT | |
| 19a3 | PUSH2 | 0x19a9 |
| 19a6 | JUMPI | |
| 19a7 | POP | |
| 19a8 | JUMP | |
| 19a9 | JUMPDEST | |
| 19aa | DUP3 | |
| 19ab | PUSH4 | 0x05bc2167 |
| 19b0 | PUSH1 | 0xe5 |
| 19b2 | SHL | |
| 19b3 | PUSH0 |