import { BootstrapResult } from './personhood/bootstrap.js'; import { PopSelfServeConfig } from './environments.js'; import { NonRetryableError } from './errors.js'; import { PolkadotSigner } from 'polkadot-api'; import { DotnsAbiProfile, DotnsPricingInput } from './dotns-protocol.js'; import './personhood/bind-personal-id.js'; import './personhood/claim-pgas.js'; import './personhood/bind-paid-alias.js'; import './personhood/chain-prereqs.js'; /** One step in the phone-signature plan fired at preflight. */ type PhoneSignatureStep = "Commitment" | "Register" | "Link content"; interface DotNSConnectOptions { rpc?: string; keyUri?: string; mnemonic?: string; derivationPath?: string; signer?: PolkadotSigner; signerAddress?: string; /** * Optional override for the Asset Hub RPC failover list. When provided, the * primary RPC (this.rpc) is followed by these endpoints for retries. When * omitted, the legacy hardcoded RPC_ENDPOINTS list (paseo) is used — * preserves backwards-compatibility for external library consumers. The * bulletin-deploy CLI passes the list resolved from environments.json so * `--env ` drives both bulletin and asset-hub endpoints. */ assetHubEndpoints?: string[]; autoAccountMapping?: boolean; nativeToEthRatio?: bigint; contracts?: Record; /** Optional environment ID (e.g. "paseo-next-v2"). Used in shell command examples in error messages. */ environmentId?: string; /** * #1095: the resolved env's environments.json `network` field * ("testnet" | "mainnet"). When set, this is AUTHORITATIVE for isTestnet() * (and everything it gates — attemptTestnetTopUp's Alice/Bob dev-phrase * spend, the NoStatus self-grant path) and is never overridden by a chain * spec_name read. Omit (or pass an env-less/custom RPC) to fall back to * the spec_name-based detection, unchanged from before this issue. */ network?: string; /** Optional PoP self-serve config resolved from environments.json. Gates state-aware and generic testnet guidance blocks. */ popSelfServe?: PopSelfServeConfig | null; /** Optional override for the storage deposit required for a fresh TLD register(). Loaded from environments.json per-env. */ registerStorageDeposit?: bigint; /** * Optional per-environment DotNS TLD (e.g. "paseo" on paseo-next-v2; "dot" * on previewnet) — see environments.json's per-env `tld` field. When * omitted, connect() reads DotnsProtocolRegistry.tld() on-chain instead of * silently assuming a default (dotns PR #218); that read itself falls back * to DEFAULT_TLD ("dot") only when it COMPLETES but reverts or returns * empty data (pre-#218 deployment). See resolveTldFromRegistryResult. */ tld?: string; /** * Called immediately before each on-chain transaction that requires an * interactive mobile wallet approval. Only wired in when the session signer * is active; pool/mnemonic paths leave this unset. */ onPhoneSigningRequired?: (label: string) => void; /** * Human-ready gate. Awaited immediately BEFORE each phone signature request * is sent. Resolve when the human is at their phone and ready; reject/throw * to abort. The per-signature operation timeout starts only AFTER this * resolves. `attempt` >= 2 means a re-sign (principle 4). * * `approvalBudgetMs` (#194) discloses how long the human has to approve * before the watcher gives up as silent (see PHONE_APPROVAL_MS) — the * caller should surface it in the prompt so the deadline is never a * surprise. `reason: "silence"` (#194) marks the re-arm case: the watcher * went silent with no prior event and the caller is re-prompting instead of * failing the run outright (see PHONE_SILENCE_MAX_REARMS); undefined/"resign" * keeps today's "Re-sign needed" wording for the verifyEffect-false-negative * re-sign case. */ confirmPhoneReady?: (ctx: { label: string; attempt: number; total: number; approvalBudgetMs: number; reason?: "resign" | "silence"; }) => Promise; /** * True when the injected signer is a real phone/session signer that needs the * human-ready gate (`_awaitPhoneReady`). False (default) for local workers used * in transfer mode and mnemonic signers — those sign in-process with no phone. * * Fixes #980: `_usesExternalSigner` is true for the local transfer-worker too, * so it cannot distinguish phone-backed from in-process. This flag is the * transfer-aware predicate that `isPhoneSignerActive` in deploy.ts already uses. */ phoneSigner?: boolean; /** * Optional per-environment pin for the DotNS ABI profile (e.g. from * environments.json's per-env `dotnsProtocol` field). ASSERTED against the * live connect()-time probe, never used to override it — connect() throws * naming both values when they disagree. A pin that silently overrode the * probe would recreate exactly the "addresses are identical across * generations so nothing flags a drift" failure this detection exists to * prevent (2026-09-01 outage). Not wired from environments.json yet — that * plumbing is a follow-up; this option exists so connect() can already * honour it once it is. */ dotnsProtocol?: DotnsAbiProfile; } interface OwnershipResult { owned: boolean; owner: string | null; } interface AuthorizationResult { authorised: boolean; owner: string | null; } declare const TX_KIND_HASH: "hash"; declare const TX_KIND_NONCE_ADVANCED: "nonce-advanced"; declare const TX_KIND_BEST_BLOCK: "best-block"; declare const ATTR_TX_RESOLUTION_KIND = "deploy.dotns.tx_resolution_kind"; type TxResolution = { kind: typeof TX_KIND_HASH; hash: string; block?: { hash: string; number: number; }; } | { kind: typeof TX_KIND_NONCE_ADVANCED; rpc: string; } | { kind: typeof TX_KIND_BEST_BLOCK; }; declare const TX_KIND_SKIPPED: "skipped"; /** * Pure skip-decision for `setTextRecord`'s already-set pre-check (#1168): * true when the on-chain value already equals the target, meaning the write * can be skipped entirely. Mirrors setContenthash's inline `current === expected` * check, extracted here so the decision is unit-testable without a live chain. */ declare function shouldSkipTextWrite(current: string, target: string): boolean; interface PriceValidationResult { priceWei: bigint; requiredStatus: number; userStatus: number; message: string; /** * The PopRules.pricingVersion() this price was resolved against — set only * on the v0.5.8-rc1 profile (needsPricingBeforeCommit), where the * committed registration tuple must carry the SAME version this price came * from. Undefined on the poprules-startingPrice profile, where pricing has * no versioning concept. */ pricingVersion?: bigint; } interface ParsedDomainName { isSubdomain: boolean; label: string; sublabel: string | null; parentLabel: string | null; fullName: string; } interface DotnsPreflightResult { label: string; classification: { status: number; message: string; }; userStatus: number; trailingDigits: number; baselength: number; isAvailable: boolean; existingOwner: string | null; isBaseNameReserved: boolean; reservationOwner: string | null; isTestnet: boolean; canProceed: boolean; reason?: string; plannedAction: "register" | "already-owned-by-us" | "already-owned-by-recipient" | "abort"; needsPopUpgrade: boolean; targetPopStatus?: number; /** Free PAS balance of the DotNS signer at preflight time, in plancks (10 decimals). */ signerFreeBalance?: bigint; /** Threshold the signer must clear; depends on plannedAction. */ feeFloor?: bigint; /** Set when an auto-top-up was attempted on testnet; describes the source and amount. */ toppedUp?: { source: "Alice" | "Bob"; transferred: bigint; }; } declare const MINIMUM_REGISTER_STORAGE_DEPOSIT = 2000000000000n; declare function registerDepositWei(userStatus: number, startingPriceWei: bigint): bigint; declare function bufferedWeiToNative(weiValue: bigint, nativeToEthRatio: bigint): bigint; declare function weiToNative(feeWei: bigint, nativeToEthRatio: bigint): bigint; declare function fmtPas(plancks: bigint): string; type DotnsSuccessAction = Exclude; declare function feeFloorFor(plannedAction: DotnsSuccessAction, storageDeposit?: bigint, rentPriceNative?: bigint, transferFeeNative?: bigint): bigint; declare const RPC_ENDPOINTS: string[]; declare const CONTRACTS: { readonly DOTNS_REGISTRAR: "0x329aAA5b6bEa94E750b2dacBa74Bf41291E6c2BD"; readonly DOTNS_REGISTRAR_CONTROLLER: "0xd09e0F1c1E6CE8Cf40df929ef4FC778629573651"; readonly DOTNS_REGISTRY: "0x4Da0d37aBe96C06ab19963F31ca2DC0412057a6f"; readonly DOTNS_RESOLVER: "0x95645C7fD0fF38790647FE13F87Eb11c1DCc8514"; readonly DOTNS_CONTENT_RESOLVER: "0x7756DF72CBc7f062e7403cD59e45fBc78bed1cD7"; readonly DOTNS_REVERSE_RESOLVER: "0x95D57363B491CF743970c640fe419541386ac8BF"; readonly STORE_FACTORY: "0x030296782F4d3046B080BcB017f01837561D9702"; readonly POP_RULES: "0x4e8920B1E69d0cEA9b23CBFC87A17Ee6fE02d2d3"; }; declare const DECIMALS: bigint; declare const NATIVE_TO_ETH_RATIO: bigint; declare const CONNECTION_TIMEOUT_MS: number; declare const REVIVE_ADDRESS_ATTEMPTS: number; declare const CONTENTHASH_VERIFY_ATTEMPTS: number; declare function pickVerifyEndpoint(attempt: number, rpc: string | null, assetHubEndpoints: string[]): string; declare const OPERATION_TIMEOUT_MS: number; declare const TX_TIMEOUT_MS: number; declare const TX_CHAIN_TIME_BUDGET_MS: number; declare const TX_WALL_CLOCK_CEILING_MS: number; declare const TX_NO_PROGRESS_MS: number; declare const PHONE_APPROVAL_MS: number; declare const DOTNS_BEST_BLOCK_GRACE_MS: number; declare const WS_HEARTBEAT_TIMEOUT_MS: number; declare const DOTNS_TX_MAX_ATTEMPTS: number; /** * Thrown by signAndSubmitExtrinsic when the transaction watcher goes silent * with NO prior event — i.e. the chain never received a "signed" / "broadcasted" * event before the silence deadline. On the phone/session-signer path this * typically means the user hasn't approved the request on their phone yet. * Typed separately from a plain Error so signAndSubmitWithRetry can apply a * different policy — fast-fail (#990, backported from polkadot-app-deploy) * followed by a bounded re-arm one layer up (#194: see PHONE_SILENCE_MAX_REARMS * and DotNS.contractTransaction) — instead of the default retry/backoff loop. */ declare class WatcherSilentNoEventError extends Error { constructor(silentMs: number); } declare const VERIFY_EFFECT_CHAIN_SECONDS: number; declare const NONCE_ADVANCE_VERIFY_RETRIES: number; declare const NONCE_ADVANCE_VERIFY_RETRY_INTERVAL_MS: number; declare function verifyEffectWithGrace(verifyEffect: () => Promise, { retries, intervalMs }?: { retries?: number; intervalMs?: number; }): Promise; declare function classifyTxRetryDecision(err: unknown): "retry" | "abort"; /** * Distinct subclass of NonRetryableError (not a plain one) so a caller can * identify "this specific failure is eligible for a bounded human re-arm" * without string-matching an error message. Anything that merely checks * `instanceof NonRetryableError` (e.g. bin/bulletin-deploy's exit-code * branch, or the existing #990 tests) is unaffected — this IS one. */ declare class PhoneSilenceNonRetryableError extends NonRetryableError { } /** * Phone-signer no-event classification (#990, backported from * polkadot-app-deploy; call-site behaviour updated by #194). * WatcherSilentNoEventError means the watcher never saw a single prior event — * the phone never approved the request — which is a materially different * situation from a WS stall after signing. For a phone signer, generic * attempt/backoff retry would just pay another ~90s of silence for no better * odds (the phone still won't have approved), so this returns a * PhoneSilenceNonRetryableError to keep signAndSubmitWithRetry's generic * retry loop from running. * That does NOT mean the run ends here, though: DotNS.contractTransaction * (NOT signAndSubmitWithRetry — see the comment there for why) treats this * classification as "eligible for a bounded human re-arm": when it's a real * phone signer with a phoneLabel, it re-prompts and resubmits up to * PHONE_SILENCE_MAX_REARMS times before giving up with this exact error, * since the storage work is already sunk (paid + finalised) by this point and * forcing a full re-deploy is strictly worse than asking the human to look at * their phone again. * Non-phone signers, or a WatcherSilentNoEventError instance not present (e.g. * a plain "watcher silent" Error where a prior event DID arrive), fall through * to the default classifyTxRetryDecision/retry path unchanged. Pure so the * classification is unit-testable without driving a real retry loop — the * re-arm loop itself lives at the call site, not here. */ declare function classifyWatcherSilentFastFail(err: unknown, isPhoneSigner: boolean | undefined): PhoneSilenceNonRetryableError | null; declare const PHONE_SILENCE_MAX_REARMS: number; type PhoneOnResign = (attempt: number, reason?: "resign" | "silence") => Promise; declare function dotnsRetryBackoffMs(attempt: number, rand?: () => number): number; /** * Run `fn` up to `attempts` times, backing off between failures. Returns the * first success; rethrows the LAST error if every attempt fails. `sleep` and * `backoffMs` are injectable so the retry policy is unit-testable without real * timers. Used for the ReviveApi.address resolution in connect() (#1131) — a * generic seam so the "retry N times with backoff" behaviour is tested once, * independent of the live-chain call it wraps. */ declare function withRetry(fn: (attempt: number) => Promise, opts: { attempts: number; onRetry?: (attempt: number, err: unknown, backoffMs: number) => void; backoffMs?: (attempt: number) => number; sleep?: (ms: number) => Promise; }): Promise; /** * Whether a failed attempt should be retried: only when the error is * retry-eligible AND there's a later attempt left in the budget. Extracted so * the loop logs EVERY failed attempt consistently (`attempt N/MAX failed`) and * the final/aborted attempt is announced rather than breaking silently — the * old loop only printed the line when a retry followed, so the last attempt was * invisible and the count appeared to stop one short. */ declare function shouldRetryTxAttempt(attempt: number, maxAttempts: number, decision: "retry" | "abort"): boolean; /** * Whether to pause for the human-ready gate before a retry RE-SIGN (#971). * Only a phone/session signer re-sign needs another tap, so the re-gate fires * only on attempt ≥ 2 (a re-sign, not the first sign) AND when the signer is a * phone signer. Local/dev workers re-sign locally and must NOT pause. Pure so * the decision is unit-testable without driving a real retry. */ declare function shouldRegateBeforeResign(attempt: number, isPhoneSigner: boolean | undefined): boolean; /** Wraps `sink` so that "failed" status events are buffered and only forwarded * when `flush()` is called (i.e. on final abort). All other statuses pass * through immediately. Call `reset()` at the top of each retry attempt to * discard a buffered "failed" from the previous attempt. * * Also deduplicates "included": papi's txBestBlocksState subscription can fire * with found=true multiple times (tx can appear/reappear across best-block * updates), so without dedup the status line prints twice (#891). "included" is * passed through only once per attempt; reset() clears the seen flag so the * next attempt can emit it again if it succeeds through a different path. * * Closes two leak paths (issue #704): * 1. Retry-recovered: attempt N emits "failed" before throwing; a later attempt * succeeds → reset() at the top of the next iteration discards the buffer, * and flush() is never called on the success return → sink never sees it. * 2. Late watcher event: papi can emit a delayed drop/reorg after * signAndSubmitExtrinsic has already resolved with "finalized"; the buffer * is never flushed on the success path → silently dropped. */ declare function makeRetryStatusFilter(sink: (status: string) => void): { callback: (status: string) => void; flush: () => void; reset: () => void; }; declare const DEFAULT_MNEMONIC: string; declare const DEFAULT_TLD: string; declare const DEFAULT_DOTNS_PROFILE: DotnsAbiProfile; declare const KNOWN_TLDS: readonly string[]; /** * Outcome of a DotnsProtocolRegistry dry-run read. `ok: false` means the dry * run COMPLETED (the chain replied) but reverted, returned empty `0x`, or no * registry address was configured for this env — every one of those * collapses to the same "can't determine on-chain state" signal. It does * NOT mean the call threw — a throw (network/RPC failure) must propagate * past this type entirely, never get wrapped into `{ ok: false }`. */ type RegistryDryRunResult = { ok: true; value: T; } | { ok: false; }; declare function normalizeOnChainTld(raw: string): string; declare function stripTldSuffix(input: string, tld: string): string; declare function resolveTldFromRegistryResult(result: RegistryDryRunResult): string; declare function checkTldNodeConsistency(tld: string, result: RegistryDryRunResult): void; declare function fetchNonce(rpc: string | string[], ss58Address: string): Promise; declare function verifyNonceAdvanced(endpoints: string[], ss58Address: string, originalNonce: number): Promise<{ advanced: true; witnessRpc: string; } | { advanced: false; }>; declare function nonceContentionBackoffMs(attempt: number, rand?: () => number): number; declare const DOTNS_NONCE_CONTENTION_MAX_ATTEMPTS: number; declare function isNonceContentionAmbiguous(err: unknown): boolean; /** * #1158: bounded nonce re-acquisition for the ambiguous nonce-advance-fallback * case on the zero-config write path, where concurrent deploys share ONE Asset * Hub nonce space (the bare default signer, no derivation). When a sibling * deploy's tx consumes the nonce slot our own tx was built against, * `resubmit()` rejects with the ambiguous message (nonce advanced, but our * effect isn't observable) instead of resolving. The old code fell through to * signAndSubmitWithRetry's general retry loop, which reused the SAME stale * nonceFallback.expectedNonce on every attempt — so the very next attempt's * first poll tick saw "nonce already > (still-stale) N" and rejected again * near-instantly, before its own freshly-submitted tx had any chance to land. * That thrashing is the real #1158 repro. * * Fix: re-fetch the LIVE account nonce (never the stale expectedNonce a prior * attempt was built against) so the next resubmit has a real chance to land, * wait a short jittered backoff so concurrent siblings de-sync rather than * lock-stepping onto the same slot again, and bound the whole thing to * `maxAttempts` so a genuinely unlandable write fails FAST with a clear, * actionable terminal error. * * `resubmit` is a full rebuild+sign+watch cycle — its own outcome already * encodes the nonce-advance detection + verifyEffectWithGrace re-polls, so * this function only decides whether/how to retry it; it never re-implements * that detection. A resubmit failure that is NOT the ambiguous case (e.g. a * websocket blip) is rethrown as-is — folding a genuinely different failure * into the contention loop's own message would mask the real cause. */ declare function reacquireNonceOnContention(resubmit: () => Promise, nonceFallback: { rpcs: string[]; senderSS58: string; expectedNonce: number; }, label: string, opts?: { fetchNonce?: (rpcs: string[], ss58: string) => Promise; sleep?: (ms: number) => Promise; backoffMs?: (attempt: number) => number; maxAttempts?: number; }): Promise; declare const ProofOfPersonhoodStatus: { readonly NoStatus: 0; readonly ProofOfPersonhoodLite: 1; readonly ProofOfPersonhoodFull: 2; readonly Reserved: 3; }; declare class ContractDryRunRevertError extends Error { revertData: `0x${string}`; revertFlags: bigint; constructor(message: string, revertData: `0x${string}`, revertFlags: bigint); } declare function convertToHexString(value: unknown): string; declare function formatContractDryRunFailure(gasEstimate: { revertData?: string; revertFlags?: bigint; gasConsumed?: { referenceTime: bigint; proofSize: bigint; }; gasRequired?: { referenceTime: bigint; proofSize: bigint; }; storageDeposit?: bigint; }, context: { contractAddress: string; functionName?: string; signerSubstrateAddress: string; signerEvmAddress?: string; value: bigint; encodedData: string; args?: unknown[]; contracts?: Record; }): string; declare function __formatContractDryRunFailureForTest(gasEstimate: Parameters[0], context: Parameters[1]): string; declare function convertWeiToNative(weiValue: bigint): bigint; declare function computeDomainNode(label: string, tld?: string): `0x${string}`; declare function computeDomainTokenId(label: string, tld?: string): bigint; declare function computeSubnodeIds(sublabel: string, parentLabel: string, tld?: string): { parentNode: `0x${string}`; subnode: `0x${string}`; }; declare function assertNotZeroRecipient(toH160: string, fullName: string): void; declare function countTrailingDigits(label: string): number; declare function stripTrailingDigits(label: string): string; declare function sanitizeDomainLabel(label: string): string; interface DomainLabelAlternative { label: string; baseLength: number; status: number; tierDescription: string; } declare function buildLabelAlternatives(label: string, profile?: DotnsAbiProfile): DomainLabelAlternative[]; type Registrability = { registrable: true; } | { registrable: false; rule: "reserved-base" | "trailing-digits" | "hyphen-base"; message: string; }; declare function classifyRegistrability(label: string, profile?: DotnsAbiProfile): Registrability; declare function formatUnregistrableReason(args: { label: string; registrability: Extract; existingOwner: string | null; selfAddress: string; tld?: string; profile?: DotnsAbiProfile; }): string; declare function decideRegistrabilityOutcome(args: { label: string; registrability: Registrability; existingOwner: string | null; selfAddress: string; tld?: string; profile?: DotnsAbiProfile; }): { canProceed: boolean; plannedAction: "already-owned-by-us" | "register" | "abort"; reason?: string; }; declare function validateDomainLabel(label: string): string; declare function isCommitmentMature(chainNowSeconds: number, commitTimestampSeconds: number, minimumAgeSeconds: number): boolean; declare function isCommitmentTimingBarerevert(msg: string): boolean; declare function classifyDotnsLabel(label: string, tld?: string, profile?: DotnsAbiProfile): { status: number; message: string; }; declare function canRegister(requiredStatus: number, userStatus: number): boolean; declare function shortNamesClosedReason(label: string, baseLength: number, tld: string, environmentId: string | null | undefined): string; declare function parseDomainName(input: string, tld?: string): ParsedDomainName; declare function parseProofOfPersonhoodStatus(status: string): number; declare function popStatusName(status: number): string; declare class ReviveClientWrapper { static DRY_RUN_STORAGE_LIMIT: bigint; static DRY_RUN_WEIGHT_LIMIT: { ref_time: bigint; proof_size: bigint; }; client: any; mappedAccounts: Set; constructor(client: any); getEvmAddress(substrateAddress: string): Promise; performDryRunCall(originSubstrateAddress: string, contractAddress: string, value: bigint, encodedData: string): Promise; estimateGasForCall(originSubstrateAddress: string, contractAddress: string, value: bigint, encodedData: string): Promise; hasContractCode(address: string): Promise; checkIfAccountMapped(substrateAddress: string): Promise; ensureAccountMapped(substrateAddress: string, signer: PolkadotSigner): Promise; signAndSubmitExtrinsic(extrinsic: any, signer: PolkadotSigner, statusCallback: (status: string) => void, opts?: { nonceFallback?: { rpcs: string[]; senderSS58: string; expectedNonce: number; }; verifyEffect?: () => Promise; feeAsset?: "pgas"; isPhoneSigner?: boolean; }): Promise; signAndSubmitWithRetry(buildExtrinsic: () => any, signer: PolkadotSigner, statusCallback: (status: string) => void, label: string, opts?: { nonceFallback?: { rpcs: string[]; senderSS58: string; expectedNonce: number; }; verifyEffect?: () => Promise; feeAsset?: "pgas"; isPhoneSigner?: boolean; onResign?: PhoneOnResign; fetchNonce?: (rpcs: string[], ss58: string) => Promise; sleep?: (ms: number) => Promise; nonceContentionBackoffMs?: (attempt: number) => number; }): Promise; private dryRunReviveCall; submitTransaction(contractAddress: string, value: bigint, encodedData: string, signerSubstrateAddress: string, signer: PolkadotSigner, statusCallback: (status: string) => void, { rpcs, useNoncePolling, functionName, args, contracts, verifyEffect, feeAsset, isPhoneSigner, onResign }: { rpcs: string[]; useNoncePolling?: boolean; functionName?: string; args?: unknown[]; contracts?: Record; verifyEffect?: () => Promise; feeAsset?: "pgas"; isPhoneSigner?: boolean; onResign?: (attempt: number) => Promise; }): Promise; submitBatchedTransactions(calls: { contractAddress: string; value: bigint; encodedData: string; functionName?: string; args?: unknown[]; }[], signerSubstrateAddress: string, signer: PolkadotSigner, statusCallback: (status: string) => void): Promise; } /** * Formats a papi 2.x dispatchError object into a readable string. * papi typed enums default .toString() returns "[object Object]"; this * serialises the structure with BigInt-safe JSON so error messages are * useful for debugging (e.g. {type:"Module",value:{type:"Revive",...}}). */ declare function formatDispatchError(err: unknown): string; type AliasAccountState = "not-bound" | "bound-likely-stale" | "wrong-context" | "bound-fresh"; interface AliasAccountClassification { state: AliasAccountState; storedContextHex?: string; paid?: boolean; revision?: number; } /** * Pure classifier — interprets an `AliasAccounts.AccountToAlias` storage row * (or `undefined` for "no row") and returns the alias-state classification. * * Split out from `classifyAliasAccountState` so the row → state mapping can * be unit-tested without a chain connection. * * AliasAccounts pallet rewrite (paritytech/individuality#955, May 2026) * collapsed the paid/free path split — every binding now pays `AliasFee` * and the `paid` field no longer exists on the row. Classification keys * on context alone: rows under the `dotns` context are heuristically * flagged stale for reprove; rows under any other context are wrong-context; * absent rows are not-bound. See docs-internal/dotns-bootstrap-handover.md * §3 for the pallet contract. */ declare function classifyAliasAccountRow(row: unknown): AliasAccountClassification; /** * Format a user-facing remediation message for the "no personhood" preflight failure. * Pure function — unit-testable without a chain connection. * * When popSelfServe.stateAwareGuidance is true, returns actionable advice based on alias state. * Otherwise falls back to the generic "contact DotNS team" message. * * The environmentId parameter is forwarded for use in shell command examples (e.g. * `--env paseo-next-v2`) so users can copy-paste the correct env id. It does NOT gate * the state-aware branch — that is controlled by popSelfServe.stateAwareGuidance. */ declare function formatPersonhoodRemediation(state: AliasAccountClassification, popSelfServe: PopSelfServeConfig | null, environmentId: string | null): string; /** * Build a complete user-facing PoP shortfall reason string. * Pure function — unit-testable without a chain connection. * * Composes: * 1. Lead-in from the caller (`${label}.dot requires X, but signer is Y.`) * 2. State-tailored guidance (when isTestnet && popSelfServe.stateAwareGuidance === true) * — delegates to formatPersonhoodRemediation for state-specific text. * — When aliasState is null on a stateAwareGuidance env, treated as "not-bound". * 3. When isTestnet && popSelfServe != null but stateAwareGuidance is false/absent: * the generic 3-step self-serve bootstrap block using the env's config URLs/label. * 4. When isTestnet && popSelfServe == null: no testnet block (env opted out). * 5. Always: the "Alternatives" block (NoStatus-compatible label + whitelist link). */ declare function formatPopShortfallReason(opts: { label: string; requiredName: string; currentName: string; isTestnet: boolean; environmentId: string | null; popSelfServe: PopSelfServeConfig | null; aliasState: AliasAccountClassification | null; exampleNoStatusLabel: string; tld?: string; }): string; declare class DotNS { client: any | null; clientWrapper: ReviveClientWrapper | null; rpc: string | null; substrateAddress: string | null; evmAddress: string | null; signer: PolkadotSigner | null; connected: boolean; assetHubEndpoints: string[]; private _usesExternalSigner; /** True only when the signer is a real phone/session signer that needs `_awaitPhoneReady`. */ private _isPhoneSigner; private _localMnemonic; private _contracts; private _nativeToEthRatio; private _environmentId; private _network; private _popSelfServe; private _registerStorageDeposit; private _tld; private _protocolVersion; private _adapter; private _subnodeOwnerShape; private _shortNamesEnabled; private _onPhoneSigningRequired; private _confirmPhoneReady; /** Total phone-signature count for this DotNS session (drives the `total` field passed to confirmPhoneReady). */ private _phoneSignatureTotal; /** Running attempt counter per label for re-sign detection. Reset at connect/disconnect. */ private _phoneSignatureAttempts; /** Samples Asset Hub block rate / finality lag / RPC latency for the life of this connection. */ private readonly chainHealth; private _classifyOverrideForTest; /** Test-only: inject a fixed classifyAliasAccountState return value for the next call. Consumed once. */ __setClassifyOverrideForTest(state: AliasAccountState): void; private _userPopStatusOverrideForTest; /** Test-only: inject a fixed getUserPopStatus return value for the next call. Consumed once. */ __setUserPopStatusForTest(status: number): void; private _reproveFallbackForTest; /** Test-only: register a fallback reprove result used if the real reprove() throws (e.g. "already at latest revision", or a transient chain error). Consumed once. */ __setReproveFallbackForTest(result: { oldRevision: number; newRevision: number; blockHash: string; }): void; /** The DotNS ABI profile detected by connect()'s live probe (readonly; for telemetry and tests). Defaults to "poprules-startingPrice" before connect() runs — see the field's own comment. */ get protocolVersion(): DotnsAbiProfile; /** Test-only: bypass connect()'s live probe and pin the adapter directly, for unit tests that stub chain calls without going through connect(). */ __setProtocolVersionForTest(profile: DotnsAbiProfile): void; /** Test-only: pin the cached PopRules.shortNamesEnabled value so a scenario can reach the personhood branch for a 6-8 char label on a chain where the band is closed. */ __setShortNamesEnabledForTest(value: boolean | "unknown" | null): void; /** #1435 test-only: pin the setSubnodeOwner shape cache directly ("legacy", "v07", or null to force resolveSubnodeOwnerShape to re-probe), bypassing the live dry-run probe — for unit tests that stub the probe or exercise the fallback/caching logic itself. */ __setSubnodeOwnerShapeForTest(shape: "legacy" | "v07" | null): void; constructor(); /** * The authoritative, post-connect resolved TLD: `options.tld` when the env * configured one, otherwise whatever `connect()` read from * `DotnsProtocolRegistry.tld()` (or `DEFAULT_TLD` if that read completed * but was unusable — see resolveTldFromRegistryResult). Callers that need * to reflect the REAL on-chain TLD in display strings after connect() — * rather than a possibly-wrong pre-connect default — should read this * getter instead of re-deriving their own value. */ get tld(): string; /** * Module-scope memoization for the tldNode() consistency check (#218 perf * fix): once `checkTldNodeConsistency` has completed — verified match, or * `{ok:false}` (pre-#218 registry / none configured) — for a given * (registryAddress, tld) pair, every later connect() against that same * pair in this process skips the `tldNode()` dry-run round trip entirely. * A single deploy() can construct up to three DotNS instances against the * SAME registry, and this invariant never changes once true, so * re-verifying it over the network on every connect is pure waste on an * RPC already known to be timeout-prone under load. * * Deliberately a Set, not a cache of "did it throw" — a THROW (RPC * timeout/WS drop) must NEVER be memoized here: it has to propagate AND be * retried in full on the very next connect(), never silently treated as * "already checked". Only `.add()` calls sit after a completed dry run; * nothing on a throw path can reach one. */ private static readonly _tldNodeVerifiedCache; /** Test-only: clear the tldNode-consistency memoization cache so cases from one test don't leak into the next. */ static __resetTldNodeCacheForTest(): void; /** * Resolves `this._tld` from `options.tld` (if configured) or from the * on-chain `tld()` read, then verifies the `tldNode()` consistency * invariant for that (registry, tld) pair — skipping the invariant check * entirely when already memoized (see `_tldNodeVerifiedCache` above). * * Deliberately sequential, NOT `Promise.all`, even when `configuredTld` is * undefined and both reads are in play: the tldNode() cache is keyed on * the RESOLVED tld, so its key isn't knowable until the tld() read * completes — there is no way to consult the cache before that. Firing * both concurrently would guarantee the tldNode() round trip happens on * EVERY connect, permanently forfeiting the one saving this cache exists * for. Round-trip COUNT matters more here than wall-clock latency (the * whole motivation is an RPC already known to be timeout-prone under * load), so: await tld() first, THEN decide — on a cache hit, the * tldNode() round trip is skipped entirely. */ private resolveAndVerifyTld; /** * Tear down the current papi client (if any) and stand up a fresh WS * connection + ReviveClientWrapper against `endpoint`. Escapes a * wedged/slow/stale connection — used by connect()'s ReviveApi.address * retry (#1131) and by setContenthash's post-deploy read-back retry * (#1131-follow-up), which is the single reason this is a shared helper * rather than two copies of the same three lines. */ private recreateReviveClient; connect(options?: DotNSConnectOptions): Promise; ensureMappedAccountReady(autoAccountMapping?: boolean): Promise; ensureAutoMappedAccountReady(): Promise; ensureConnected(): void; /** * Resolve the authoritative nativeToEthRatio for this session. * * Priority: chain constant (Revive.NativeToEthRatio) > options.nativeToEthRatio > default. * On mismatch between the env-configured value and the chain value, logs a WARNING naming * both values and proceeds with the chain value (it is the source of truth). * On query failure, falls back to the configured/default value without throwing. * * Must be called after clientWrapper is established (i.e. inside connect()). */ resolveNativeToEthRatio(options: DotNSConnectOptions): Promise; private _testnetCache; isTestnet(): Promise; /** * Classify the AliasAccounts state for a substrate address. * Only called on paseo-next-v2 testnets inside the preflight's NoStatus branch. * Returns "not-bound" if the chain is unreachable (safe fallback to generic advice). */ private classifyAliasAccountState; readFreeBalance(ss58: string): Promise; attemptTestnetTopUp(recipientSs58: string, targetAmount: bigint): Promise<{ source: "Alice" | "Bob"; transferred: bigint; } | null>; private submitTransfer; /** * Low-level dry-run read against DotnsProtocolRegistry (tld() / tldNode()). * Deliberately does NOT reuse contractCall/contractCallNullable: both of * those throw on a revert or on empty data, which would make "contract * doesn't support this function yet" indistinguishable from "the RPC call * itself never completed" — exactly the distinction resolution step 3 * depends on. Here: * - no DOTNS_PROTOCOL_REGISTRY address configured → { ok: false } * (nothing to call; treated the same as "not supported"). * - the dry run COMPLETES (chain replied) but reverts, or returns empty * `0x` → { ok: false } (pre-#218 deployment, e.g. previewnet today). * - `performDryRunCall` itself THROWS (RPC timeout, WS drop, connection * error) → NOT caught here; propagates to the caller. Collapsing that * into { ok: false } would make a network blip indistinguishable from * "pre-#218", silently defaulting to the wrong TLD on a live env with * no revert and no error — the worst failure mode in this whole change. */ private dryRunRegistryString; /** * Low-level "did this view function answer" probe, used by the DotNS * protocol-version detection below. Same non-throwing-on-revert posture as * dryRunRegistryString and for the same reason: "the function doesn't * exist on this generation" (a revert or empty data) must be * distinguishable from "the RPC call itself never completed" (a THROW, * which propagates here — a network blip must never be silently read as * "this probe says no"). */ private probeViewFunctionOk; /** * Shared dry-run mechanics for both dryRunRegistryString and * probeViewFunctionOk (#1350): encode the call, dry-run it, and report * whether it completed successfully with non-empty return data — the * revert-vs-RPC-failure boundary both callers exist to draw. A dry run * that reverts or returns empty `0x` comes back as `{ ok: false }`. * `performDryRunCall` itself THROWING (RPC timeout, WS drop, connection * error) is NOT caught here and propagates to the caller — same posture as * before this was extracted. */ private performViewDryRun; /** * Detect the live DotNS ABI profile by probing POP_RULES — never by * trusting configured addresses, since CREATE3 keeps them identical across * generations (the exact reason the 2026-09-01 outage went unflagged by the * address-drift guardrail). Dry-run read only: no transactions, no state * writes. Caches nothing itself — connect() calls this once per instance * and stores the result on _protocolVersion/_adapter. * * All three-valued classification lives in classifyProtocolVersion * (dotns-protocol.ts) — this method just gathers the inputs and passes * hasContractCode's result through UNFLATTENED (paritytech/bulletin-deploy * #1349: an earlier `hasCodeResult === true` check here silently collapsed * `null` — "code presence unverified", e.g. a transient RPC blip — into * `false`/"no code", aborting every connect() on a single flaky read). * hasContractCode and both probes have no data dependency on each other in * the common (code-present) case — a probe answering is itself positive * proof the contract is there regardless of what hasContractCode says — so * all three run in one Promise.all rather than gating the probes behind * hasContractCode resolving first. * * A fourth probe (isPopIssued, against DOTNS_POP_CONTROLLER — see * DotnsProtocolProbe.isPopIssuedOk's own comment) runs in the SAME * Promise.all, not after: it's the only thing that tells v0.6.0 apart from * v0.5.8-rc1 (pricingVersion answers on both), and classifyProtocolVersion * already only consults it when pricingVersionOk is true, so gating it * behind that result resolving first would just add a serialized * round-trip for no benefit — worse as v0.6.0 spreads (#1410), since that * "no benefit" case becomes the common one. The discarded-probe cost does * NOT self-liquidate the moment v0.6.0 ships: it persists on every * environment still running an older generation (dotns-protocol.ts's * profile comment owns per-generation status — this one does not restate * it). Parallel regardless: one discarded read beats a serialized * round-trip on every connect. Resolves to `null` * immediately (no RPC at all) when DOTNS_POP_CONTROLLER has no configured * address. */ private detectProtocolVersion; contractCall(contractAddress: string, contractAbi: readonly any[], functionName: string, args?: any[]): Promise; /** * Like contractCall, but returns null when the chain replies with empty data * ("0x"). Use this for view functions where an unset storage slot is a * meaningful answer (e.g. resolver(node) for a name with no resolver, * text records, optional ownership lookups). Use the strict contractCall * for read paths that must always return a value. */ contractCallNullable(contractAddress: string, contractAbi: readonly any[], functionName: string, args?: any[]): Promise; contractTransaction(contractAddress: string, value: bigint, contractAbi: readonly any[], functionName: string, args?: any[], statusCallback?: (status: string) => void, { useNoncePolling, verifyEffect, feeAsset, phoneLabel }?: { useNoncePolling?: boolean; verifyEffect?: () => Promise; feeAsset?: "pgas"; phoneLabel?: string; }): Promise; /** * PopRules gates short names with `require(shortNamesEnabled || baseLength >= 9)`, * independently of personhood. * * `null` means no usable answer and must never be read as "off". Only a decoded * `false` closes the band; refusing a name the chain would accept is worse than * letting the chain refuse it. */ private readShortNamesEnabled; /** * #1435: resolve — once per connection — which `setSubnodeOwner` tuple * shape this chain's DOTNS_REGISTRY accepts, and cache the verdict on * `_subnodeOwnerShape` for the rest of this connection's life. Called by * buildSetSubnodeOwnerCall on the first subname write (register or * transfer, whichever runs first); every subsequent subname write in the * same connection reuses the cached shape with no further chain I/O. * * There is no read-only capability probe for this (see * DOTNS_REGISTRY_SET_SUBNODE_OWNER_ABI_V07's comment — v0.7 adds no new * function/contract to probe), so this probes the WRITE itself: dry-run * the v0.7 (5-field, `persist: true`) encoding against `sampleRecord` * first (a dry run commits no state, so this never spends a fee or * mutates the registry). Three outcomes: * * - The dry run succeeds → this chain is on v0.7+; cache "v07". * - The dry run bare-reverts (empty `0x` data, flags=1 — i.e. no * function matches this selector at all) → this chain predates v0.7; * cache "legacy" and fall back to the 4-field encoding. * - The dry run reverts WITH data → the 5-field function EXISTS and * rejected the call for a real reason (bad parent, not authorised, * etc.) — that is a genuine failure of the caller's actual write, not * a shape mismatch, so it propagates immediately rather than being * swallowed into a fallback attempt. Conflating the two here would * turn a real authorization failure into a confusing shape-probe * loop, retrying the legacy shape (which will ALSO fail, just with a * less informative bare-revert-style error) instead of surfacing the * real cause. * * `sampleRecord` is the actual record the caller is about to write (not a * throwaway probe payload) — probing with real args means a v0.7 chain * that genuinely rejects this specific write (e.g. the signer doesn't own * the parent) reports that real reason here, on the first (probe) dry * run, rather than surfacing a second time once the real submission's own * internal dry run repeats the same call. */ private resolveSubnodeOwnerShape; /** * Build the `{ abi, args }` pair a setSubnodeOwner call site should submit, * after resolving (and caching) this connection's accepted tuple shape — * see resolveSubnodeOwnerShape. `record` carries the 4 fields common to * both shapes; the v0.7 shape appends `persist: true`, which has the * registry index the subname into its owner's LabelStore. * * `persist: false` means "a registered controller will backfill the store * later", and dotns#305 enforces it (`if (!record.persist) * _onlyRegistrarController()`). A mnemonic-signed account is never a * controller, so false reverts NotAuthorised from DotNS v0.8.0 on. True * works on v0.7 too, because the registry performs the store write and * StoreAuth.isStoreWriter admits the registry, so this needs no version gate. */ private buildSetSubnodeOwnerCall; checkOwnership(label: string, ownerAddress?: string | null): Promise; /** * Raw probe for DotnsRegistry.isAuthorised(node, account) — returns the * decoded bool when the accessor exists, or `null` when it is absent from * this registry deployment (a bare selector-not-found revert). Shares the * bare-revert-vs-real-revert discrimination (isBareRevertResult) with * resolveSubnodeOwnerShape's v0.7 shape probe above: a revert WITH data * means the function exists and the on-chain call itself is a normal view * read that should never revert for a real reason (see _isAuthorised in * DotnsRegistry.sol — it only ever returns a bool), so that branch * propagates as an unexpected failure rather than being folded into * "absent". */ private probeIsAuthorised; /** * Ask the registry who may write `node`, per DotnsRegistry.isAuthorised — * the contract's own "single source of truth" for owner-gated entry * points (setSubnodeOwner, setSubnodeResolver, setResolver): a non-zero * stored subnode owner must equal `account`; otherwise, for a tokenised * node, the registrar's ERC-721 owner, an operator-for-all delegate, or a * single-token approval all qualify. Strictly wider than a raw * owner()-equality test, which refuses an approved/operator delegate the * chain would accept — the contract's own comment calls operator-for-all * "the common marketplace / escrow delegation path". * * Falls back to owner()-equality when isAuthorised is absent from this * registry deployment (a bare revert on the probe) so a missing accessor * never turns into a refusal. `owner` is always the node's registry-read * owner (for informative messaging), independent of which path decided * `authorised`. */ checkNodeAuthorization(node: string, account: string): Promise; /** Live transfer-fee quote. transferFloor is a pure PopRules view — it * classifies the label and reads both tiers, so it works BEFORE the name is * registered (unlike quoteTransferFee, which reverts on an unregistered token). */ quoteTransferFloorNative(label: string, fromH160: string, toH160: string): Promise<{ feeWei: bigint; feeNative: bigint; }>; /** Hand `label`.dot from the connected signer (the worker, current owner) to * `toH160`, paying the transferFloor friction fee. Idempotent: a no-op if the * recipient already owns it; errors if a third party does. */ transferName(label: string, toH160: string, statusCallback?: (status: string) => void): Promise<{ status: "ok" | "skipped-already-owned"; txHash?: string; feeWei?: bigint; }>; /** Reassign an existing subname (e.g. `app.foo.`) to `toH160`. * * Subnames are NOT ERC-721 tokens, so they cannot go through * transferName/transferFrom — the registrar has no token for them. Instead * the *parent-domain* owner reassigns a subname via the registry's * setSubnodeOwner (the same call registerSubdomain uses to create it). * Authorisation is on the parent node, not on the subname's current owner — * checked via the registry's own isAuthorised(parentNode, account) * (checkNodeAuthorization), so the connected signer may be the parent's * owner OR an operator-for-all/single-token approval on it, matching what * the chain itself allows on setSubnodeOwner. Idempotent: a no-op when the * recipient already owns it. * * Every node here is derived via computeSubnodeIds, which routes through the * single ensNode() primitive (#1304, see the comment above ensNode) — the * same this._tld-templated convention as every other call site — * deliberately NOT a hardcoded ".dot" suffix. A second, manually-hardcoded * node-derivation path is exactly the bug class that burned production once * already (registering "ssoqedtuwf.paseo" minted the .paseo node, but a * hardcoded ".dot" lookup queried the .dot node and reverted with * ERC721NonexistentToken after an 11 PAS mint had already succeeded). */ transferSubname(sublabel: string, parentLabel: string, toH160: string, statusCallback?: (status: string) => void): Promise<{ status: "ok" | "skipped-already-owned"; txHash?: string; }>; getUserPopStatus(ownerAddress?: string | null): Promise; checkSubdomainOwnership(sublabel: string, parentLabel: string): Promise; registerSubdomain(sublabel: string, parentLabel: string): Promise<{ sublabel: string; parentLabel: string; owner: string; }>; /** * Submit multiple contract calls as a single atomic `Utility.batch_all` * extrinsic. * * Each call is encoded as a `pallet-revive::call(...)` extrinsic and * batched into one outer dispatch. The runtime executes them in * sequence and rolls back the entire batch on any inner revert. Only * the leading call is dry-run for gas — its weight is reused as the * budget for every subsequent call, on the assumption sibling * registry/resolver writes are similarly sized. */ private submitBatchedContractCalls; /** * Atomically update an executable's content CID and manifest text record. * * Hosts must never observe a new archive with the previous execution * contract (or the inverse). Both resolver calls therefore share one * `Utility.batch_all` transaction and roll back together on any failure. */ setContenthashAndTextRecord(domainName: string, contenthashHex: string, key: string, value: string): Promise<{ node: string; contenthashSkipped: boolean; textSkipped: boolean; txHash: string; }>; setContenthash(domainName: string, contenthashHex: string, opts?: { feeAsset?: "pgas"; }): Promise<{ node: string; skipped: boolean; }>; /** * Point a node's registered resolver at `DOTNS_CONTENT_RESOLVER` (RFC §Step 3.2). * * Hosts read text records via `IDotnsRegistry.resolver(node)`, so the * registered slot must point at the content resolver for manifest text * records to be discoverable. The pre-read is best-effort: pallet-revive * returns `isOk=true` with empty data when a selector isn't in the * deployed bytecode, which makes viem's decoder throw. Any decode failure * is treated as "unset" and the write fires unconditionally. `setResolver` * is idempotent against the same target, so registries that pre-date the * `resolver(bytes32)` getter just pay one extra extrinsic per publish. */ ensureContentResolver(domainName: string): Promise<{ changed: boolean; }>; /** Read a text record off `DOTNS_CONTENT_RESOLVER`. Returns `""` when unset. */ getTextRecord(domainName: string, key: string): Promise; setTextRecord(domainName: string, key: string, value: string): Promise<{ value: string; txHash: string; }>; setTextRecords(domainName: string, entries: { key: string; value: string; }[]): Promise<{ txHash: string | null; batched: boolean; }>; getContenthash(domainName: string): Promise; classifyName(label: string): Promise<{ requiredStatus: number; message: string; }>; ensureNotRegistered(label: string): Promise; generateCommitment(label: string, includeReverse?: boolean, pricing?: DotnsPricingInput): Promise<{ commitment: any; registration: any; }>; submitCommitment(commitment: any): Promise; waitForCommitmentAge(commitment: any): Promise; getPriceAndValidate(label: string): Promise; finalizeRegistration(registration: any, priceWei: bigint): Promise; verifyOwnership(label: string): Promise; preflight(label: string, opts?: { transferRecipientH160?: string; }): Promise; private _preflightInternal; private gateOnFeeBalance; register(label: string, options?: DotNSConnectOptions & { status?: string; reverse?: boolean; }): Promise<{ label: string; owner: string; }>; /** * Reprove a stale DotNS alias binding. * Opens a People-chain client internally, builds the ring proof, and submits * reprove_alias_account on AH. Use when the alias exists but the ring root * has advanced past the stored revision. * * Requires a mnemonic — the DotNS instance must have been connected with one. */ reprove(mnemonic: string): Promise<{ oldRevision: number; newRevision: number; blockHash: string; }>; /** * Run the personhood bootstrap flow for this DotNS signer. * Idempotent: each step is gated on chain state being "still needs doing". * Does NOT auto-run from preflight — call explicitly. * * Throws RecognizeRequiredError if the account hasn't been recognized by the * personhood faucet (https://sudo.personhood.dev/personhood-faucet). */ bootstrap(mnemonic: string): Promise; /** * Set the expected total number of phone signatures for this DotNS session. * Called from deploy() at preflight after computePhoneSigningSteps so that * confirmPhoneReady receives the correct `total`. */ setPhoneSignatureTotal(total: number): void; /** * Internal: await the human-ready gate then fire the "check your phone" * notification. Must be called OUTSIDE any withTimeout — the human wait is * unbounded and must never be inside the machine timeout. * * Behaviour: * - confirmPhoneReady provided → await it (counts re-signs via attempt map). * - not provided → proceed without a gate (opt-in only; an in-process * external signer, e.g. injected PolkadotSigner or mnemonic, needs no * phone gate — _usesExternalSigner alone cannot distinguish phone from * in-process). * After the gate resolves, fires onPhoneSigningRequired (the "check your * phone" notification) so the user knows the request is now being sent. * * `reason` (#194): passed straight through to confirmPhoneReady's context so * the consumer can distinguish a watcher-silence re-arm ("silence") from the * pre-existing verifyEffect-false-negative re-sign case (undefined/"resign", * which keeps rendering off `attempt` as before). */ private _awaitPhoneReady; disconnect(): void; } declare const dotns: DotNS; export { ATTR_TX_RESOLUTION_KIND, type AliasAccountClassification, type AliasAccountState, type AuthorizationResult, CONNECTION_TIMEOUT_MS, CONTENTHASH_VERIFY_ATTEMPTS, CONTRACTS, ContractDryRunRevertError, DECIMALS, DEFAULT_DOTNS_PROFILE, DEFAULT_MNEMONIC, DEFAULT_TLD, DOTNS_BEST_BLOCK_GRACE_MS, DOTNS_NONCE_CONTENTION_MAX_ATTEMPTS, DOTNS_TX_MAX_ATTEMPTS, type DomainLabelAlternative, DotNS, type DotNSConnectOptions, type DotnsPreflightResult, type DotnsSuccessAction, KNOWN_TLDS, MINIMUM_REGISTER_STORAGE_DEPOSIT, NATIVE_TO_ETH_RATIO, NONCE_ADVANCE_VERIFY_RETRIES, NONCE_ADVANCE_VERIFY_RETRY_INTERVAL_MS, OPERATION_TIMEOUT_MS, type OwnershipResult, PHONE_APPROVAL_MS, PHONE_SILENCE_MAX_REARMS, type ParsedDomainName, type PhoneSignatureStep, PhoneSilenceNonRetryableError, type PriceValidationResult, ProofOfPersonhoodStatus, REVIVE_ADDRESS_ATTEMPTS, RPC_ENDPOINTS, type Registrability, type RegistryDryRunResult, ReviveClientWrapper, TX_CHAIN_TIME_BUDGET_MS, TX_KIND_BEST_BLOCK, TX_KIND_HASH, TX_KIND_NONCE_ADVANCED, TX_KIND_SKIPPED, TX_NO_PROGRESS_MS, TX_TIMEOUT_MS, TX_WALL_CLOCK_CEILING_MS, type TxResolution, VERIFY_EFFECT_CHAIN_SECONDS, WS_HEARTBEAT_TIMEOUT_MS, WatcherSilentNoEventError, __formatContractDryRunFailureForTest, assertNotZeroRecipient, bufferedWeiToNative, buildLabelAlternatives, canRegister, checkTldNodeConsistency, classifyAliasAccountRow, classifyDotnsLabel, classifyRegistrability, classifyTxRetryDecision, classifyWatcherSilentFastFail, computeDomainNode, computeDomainTokenId, computeSubnodeIds, convertToHexString, convertWeiToNative, countTrailingDigits, decideRegistrabilityOutcome, dotns, dotnsRetryBackoffMs, feeFloorFor, fetchNonce, fmtPas, formatDispatchError, formatPersonhoodRemediation, formatPopShortfallReason, formatUnregistrableReason, isCommitmentMature, isCommitmentTimingBarerevert, isNonceContentionAmbiguous, makeRetryStatusFilter, nonceContentionBackoffMs, normalizeOnChainTld, parseDomainName, parseProofOfPersonhoodStatus, pickVerifyEndpoint, popStatusName, reacquireNonceOnContention, registerDepositWei, resolveTldFromRegistryResult, sanitizeDomainLabel, shortNamesClosedReason, shouldRegateBeforeResign, shouldRetryTxAttempt, shouldSkipTextWrite, stripTldSuffix, stripTrailingDigits, validateDomainLabel, verifyEffectWithGrace, verifyNonceAdvanced, weiToNative, withRetry };