bulletin-deploy 0.7.20 → 0.7.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -2
- package/assets/environments.json +2 -7
- package/bin/bulletin-deploy +0 -6
- package/dist/bug-report.js +4 -5
- package/dist/{chunk-GGHSZZZ3.js → chunk-2VNGK2MU.js} +13 -19
- package/dist/{chunk-UVIG5UAV.js → chunk-BFXHVC23.js} +72 -38
- package/dist/{chunk-HUT7ZGRQ.js → chunk-F36C363Y.js} +3 -11
- package/dist/{chunk-CD27FW4F.js → chunk-G2P5UIPX.js} +3 -3
- package/dist/{chunk-6LODTEG3.js → chunk-RJAFD4LO.js} +1 -1
- package/dist/{chunk-EZUICRCA.js → chunk-SA37SLYF.js} +2 -2
- package/dist/{chunk-BR2EQ2X3.js → chunk-VTTN4BX7.js} +209 -483
- package/dist/{chunk-GNVDLLZI.js → chunk-ZY6QLNKQ.js} +1 -1
- package/dist/chunk-probe.js +3 -4
- package/dist/chunker.js +0 -1
- package/dist/deploy.d.ts +1 -9
- package/dist/deploy.js +8 -9
- package/dist/dotns.d.ts +9 -33
- package/dist/dotns.js +3 -12
- package/dist/environments.d.ts +0 -4
- package/dist/environments.js +1 -2
- package/dist/errors.js +0 -1
- package/dist/gh-pages-mirror.js +0 -1
- package/dist/incremental-stats.js +0 -1
- package/dist/index.js +8 -9
- package/dist/manifest-embed.js +0 -1
- package/dist/manifest-fetch.js +0 -1
- package/dist/manifest-roundtrip.js +0 -1
- package/dist/manifest.js +0 -1
- package/dist/memory-report.js +2 -3
- package/dist/merkle.js +8 -9
- package/dist/mirror.js +0 -1
- package/dist/pool.js +0 -1
- package/dist/run-state.js +1 -2
- package/dist/telemetry.js +2 -3
- package/dist/version-check.js +3 -4
- package/docs/e2e-bootstrap.md +9 -15
- package/package.json +3 -3
- package/dist/chunk-QGM4M3NI.js +0 -37
- package/dist/wrapper-IFSKR7DG.js +0 -3651
|
@@ -5,13 +5,10 @@ import {
|
|
|
5
5
|
captureWarning,
|
|
6
6
|
setDeployAttribute,
|
|
7
7
|
withSpan
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-2VNGK2MU.js";
|
|
9
9
|
|
|
10
10
|
// src/dotns.ts
|
|
11
|
-
import { spawn } from "child_process";
|
|
12
11
|
import crypto from "crypto";
|
|
13
|
-
import { readFileSync } from "fs";
|
|
14
|
-
import { dirname, join } from "path";
|
|
15
12
|
import { createClient, Enum } from "polkadot-api";
|
|
16
13
|
import { getPolkadotSigner } from "polkadot-api/signer";
|
|
17
14
|
import { getWsProvider } from "polkadot-api/ws";
|
|
@@ -33,59 +30,6 @@ import {
|
|
|
33
30
|
concatHex
|
|
34
31
|
} from "viem";
|
|
35
32
|
import { CID } from "multiformats/cid";
|
|
36
|
-
import { createRequire } from "module";
|
|
37
|
-
var _require = createRequire(import.meta.url);
|
|
38
|
-
var DOTNS_CLI_ENV = "BULLETIN_DEPLOY_DOTNS_CLI";
|
|
39
|
-
var DOTNS_CLI_HOST_VALUES = /* @__PURE__ */ new Set(["host", "host-dispatch"]);
|
|
40
|
-
function resolveDotnsCliPackage() {
|
|
41
|
-
const cliPath = _require.resolve("@parity/dotns-cli");
|
|
42
|
-
const pkgDir = dirname(dirname(cliPath));
|
|
43
|
-
const pkg = JSON.parse(readFileSync(join(pkgDir, "package.json"), "utf-8"));
|
|
44
|
-
return { path: cliPath, version: pkg.version };
|
|
45
|
-
}
|
|
46
|
-
function resolveDotnsCliInvocation(env = process.env, packageResolver = resolveDotnsCliPackage) {
|
|
47
|
-
const override = env[DOTNS_CLI_ENV]?.trim();
|
|
48
|
-
if (override) {
|
|
49
|
-
if (DOTNS_CLI_HOST_VALUES.has(override)) {
|
|
50
|
-
return { command: process.execPath, argsPrefix: ["dotns"], version: "host-dispatch", source: "host-dispatch" };
|
|
51
|
-
}
|
|
52
|
-
return { command: override, argsPrefix: [], version: "override", source: "command-override" };
|
|
53
|
-
}
|
|
54
|
-
try {
|
|
55
|
-
const pkg = packageResolver();
|
|
56
|
-
return { command: process.execPath, argsPrefix: [pkg.path], version: pkg.version, source: "package" };
|
|
57
|
-
} catch (err) {
|
|
58
|
-
return {
|
|
59
|
-
command: process.execPath,
|
|
60
|
-
argsPrefix: ["dotns"],
|
|
61
|
-
version: "unknown",
|
|
62
|
-
source: "host-dispatch-fallback",
|
|
63
|
-
resolutionError: err instanceof Error ? err.message : String(err)
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
function describeDotnsCliInvocation(cli) {
|
|
68
|
-
if (cli.source === "package") return `${cli.command} ${cli.argsPrefix[0]}`;
|
|
69
|
-
if (cli.source === "command-override") return `${cli.command} (from ${DOTNS_CLI_ENV})`;
|
|
70
|
-
return `${cli.command} dotns`;
|
|
71
|
-
}
|
|
72
|
-
function dotnsCliFailureHint(cli) {
|
|
73
|
-
if (cli.source === "host-dispatch-fallback") {
|
|
74
|
-
return `@parity/dotns-cli was not resolvable from node_modules, so bulletin-deploy tried host binary dispatch (${process.execPath} dotns ...). Set ${DOTNS_CLI_ENV}=host to opt into that path explicitly, set ${DOTNS_CLI_ENV} to a dotns command/path, or install @parity/dotns-cli. Underlying resolution error: ${cli.resolutionError ?? "unknown"}`;
|
|
75
|
-
}
|
|
76
|
-
if (cli.source === "host-dispatch") {
|
|
77
|
-
return `${DOTNS_CLI_ENV}=host uses host binary dispatch (${process.execPath} dotns ...).`;
|
|
78
|
-
}
|
|
79
|
-
if (cli.source === "command-override") {
|
|
80
|
-
return `${DOTNS_CLI_ENV} uses a direct command/path (${cli.command}).`;
|
|
81
|
-
}
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
function withDotnsCliFailureHint(message, cli) {
|
|
85
|
-
const hint = dotnsCliFailureHint(cli);
|
|
86
|
-
return hint ? `${message}
|
|
87
|
-
${hint}` : message;
|
|
88
|
-
}
|
|
89
33
|
var ONE_PAS = 10000000000n;
|
|
90
34
|
var FEE_FLOOR_OWNED = ONE_PAS / 100n;
|
|
91
35
|
var FEE_FLOOR_REGISTER = ONE_PAS / 10n;
|
|
@@ -114,6 +58,8 @@ var CONTRACTS = {
|
|
|
114
58
|
STORE_FACTORY: "0x030296782F4d3046B080BcB017f01837561D9702",
|
|
115
59
|
POP_RULES: "0x4e8920B1E69d0cEA9b23CBFC87A17Ee6fE02d2d3"
|
|
116
60
|
};
|
|
61
|
+
var PERSONHOOD_PRECOMPILE_ADDRESS = "0x000000000000000000000000000000000a010000";
|
|
62
|
+
var PERSONHOOD_CONTEXT = "0x646f746e73000000000000000000000000000000000000000000000000000000";
|
|
117
63
|
var DECIMALS = 12n;
|
|
118
64
|
var NATIVE_TO_ETH_RATIO = 1000000n;
|
|
119
65
|
var CONNECTION_TIMEOUT_MS = 3e4;
|
|
@@ -135,7 +81,7 @@ function classifyTxRetryDecision(err) {
|
|
|
135
81
|
var DEFAULT_MNEMONIC = "bottom drive obey lake curtain smoke basket hold race lonely fit walk";
|
|
136
82
|
var _rpcIdCounter = 0;
|
|
137
83
|
async function fetchNonceFromEndpoint(rpc, ss58Address) {
|
|
138
|
-
|
|
84
|
+
if (!globalThis.WebSocket) throw new Error("WebSocket support is required to fetch nonce");
|
|
139
85
|
return new Promise((resolve, reject) => {
|
|
140
86
|
let done = false;
|
|
141
87
|
const settle = (fn, ...args) => {
|
|
@@ -149,7 +95,7 @@ async function fetchNonceFromEndpoint(rpc, ss58Address) {
|
|
|
149
95
|
fn(...args);
|
|
150
96
|
};
|
|
151
97
|
const timer = setTimeout(() => settle(reject, new Error(`fetchNonce timed out after 8s for ${rpc}`)), 8e3);
|
|
152
|
-
const ws = new
|
|
98
|
+
const ws = new WebSocket(rpc);
|
|
153
99
|
const id = ++_rpcIdCounter;
|
|
154
100
|
ws.onopen = () => ws.send(JSON.stringify({ jsonrpc: "2.0", id, method: "system_accountNextIndex", params: [ss58Address] }));
|
|
155
101
|
ws.onmessage = (e) => {
|
|
@@ -199,10 +145,30 @@ var POP_RULES_ABI = [
|
|
|
199
145
|
{ inputs: [{ name: "name", type: "string" }], name: "price", outputs: [{ name: "", type: "uint256" }], stateMutability: "view", type: "function" },
|
|
200
146
|
{ inputs: [{ name: "name", type: "string" }, { name: "userAddress", type: "address" }], name: "priceWithCheck", outputs: [{ name: "metadata", type: "tuple", components: [{ name: "price", type: "uint256" }, { name: "status", type: "uint8" }, { name: "userStatus", type: "uint8" }, { name: "message", type: "string" }] }], stateMutability: "view", type: "function" },
|
|
201
147
|
{ inputs: [{ name: "name", type: "string" }, { name: "userAddress", type: "address" }], name: "priceWithoutCheck", outputs: [{ name: "metadata", type: "tuple", components: [{ name: "price", type: "uint256" }, { name: "status", type: "uint8" }, { name: "userStatus", type: "uint8" }, { name: "message", type: "string" }] }], stateMutability: "view", type: "function" },
|
|
202
|
-
{ inputs: [{ name: "", type: "address" }], name: "userPopStatus", outputs: [{ name: "", type: "uint8" }], stateMutability: "view", type: "function" },
|
|
203
148
|
{ inputs: [{ name: "status", type: "uint8" }], name: "setUserPopStatus", outputs: [], stateMutability: "nonpayable", type: "function" },
|
|
204
149
|
{ inputs: [{ name: "name", type: "string" }], name: "isBaseNameReserved", outputs: [{ name: "isReserved", type: "bool" }, { name: "reservationOwner", type: "address" }, { name: "expiryTimestamp", type: "uint64" }], stateMutability: "view", type: "function" }
|
|
205
150
|
];
|
|
151
|
+
var PERSONHOOD_ABI = [
|
|
152
|
+
{
|
|
153
|
+
type: "function",
|
|
154
|
+
name: "personhoodStatus",
|
|
155
|
+
inputs: [
|
|
156
|
+
{ name: "account", type: "address" },
|
|
157
|
+
{ name: "context", type: "bytes32" }
|
|
158
|
+
],
|
|
159
|
+
outputs: [
|
|
160
|
+
{
|
|
161
|
+
name: "info",
|
|
162
|
+
type: "tuple",
|
|
163
|
+
components: [
|
|
164
|
+
{ name: "status", type: "uint8" },
|
|
165
|
+
{ name: "contextAlias", type: "bytes32" }
|
|
166
|
+
]
|
|
167
|
+
}
|
|
168
|
+
],
|
|
169
|
+
stateMutability: "view"
|
|
170
|
+
}
|
|
171
|
+
];
|
|
206
172
|
var DOTNS_REGISTRY_ABI = [
|
|
207
173
|
{ inputs: [{ name: "record", type: "tuple", components: [{ name: "parentNode", type: "bytes32" }, { name: "subLabel", type: "string" }, { name: "parentLabel", type: "string" }, { name: "owner", type: "address" }] }], name: "setSubnodeOwner", outputs: [{ name: "subnode", type: "bytes32" }], stateMutability: "nonpayable", type: "function" },
|
|
208
174
|
{ inputs: [{ name: "node", type: "bytes32" }, { name: "newResolver", type: "address" }], name: "setResolver", outputs: [], stateMutability: "nonpayable", type: "function" },
|
|
@@ -253,9 +219,9 @@ function extractStorageDepositCharge(rawStorageDeposit) {
|
|
|
253
219
|
if (rawStorageDeposit.value != null) return convertToBigInt(rawStorageDeposit.value, 0n);
|
|
254
220
|
return 0n;
|
|
255
221
|
}
|
|
256
|
-
function dotnsContractName(address) {
|
|
222
|
+
function dotnsContractName(address, contracts = CONTRACTS) {
|
|
257
223
|
const normalized = address.toLowerCase();
|
|
258
|
-
for (const [name, contractAddress] of Object.entries(CONTRACTS)) {
|
|
224
|
+
for (const [name, contractAddress] of Object.entries({ ...CONTRACTS, ...contracts })) {
|
|
259
225
|
if (contractAddress.toLowerCase() === normalized) return name;
|
|
260
226
|
}
|
|
261
227
|
return "unknown";
|
|
@@ -266,17 +232,13 @@ function stringifyDebugValue(value) {
|
|
|
266
232
|
function dotnsTxDebugEnabled() {
|
|
267
233
|
return process.env.BULLETIN_DEPLOY_DOTNS_DEBUG === "1" || process.env.DOTNS_DEBUG === "1";
|
|
268
234
|
}
|
|
269
|
-
function isContractRevertLike(error) {
|
|
270
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
271
|
-
return /\brevert(?:ed|ing)?\b/i.test(message);
|
|
272
|
-
}
|
|
273
235
|
function formatWeight(weight) {
|
|
274
236
|
if (!weight) return "unknown";
|
|
275
237
|
return `ref_time=${weight.referenceTime.toString()} proof_size=${weight.proofSize.toString()}`;
|
|
276
238
|
}
|
|
277
239
|
function formatContractDryRunFailure(gasEstimate, context) {
|
|
278
240
|
const functionName = context.functionName ?? "unknown";
|
|
279
|
-
const contractName = dotnsContractName(context.contractAddress);
|
|
241
|
+
const contractName = dotnsContractName(context.contractAddress, context.contracts);
|
|
280
242
|
const lines = [
|
|
281
243
|
`Contract execution would revert during ${functionName} on ${contractName}`,
|
|
282
244
|
` contract: ${context.contractAddress}`,
|
|
@@ -359,14 +321,6 @@ function validateDomainLabel(label) {
|
|
|
359
321
|
function isCommitmentMature(chainNowSeconds, commitTimestampSeconds, minimumAgeSeconds) {
|
|
360
322
|
return chainNowSeconds > commitTimestampSeconds + minimumAgeSeconds;
|
|
361
323
|
}
|
|
362
|
-
function isExplicitCommitmentBuffer(envValue) {
|
|
363
|
-
if (envValue === void 0 || envValue === "") return false;
|
|
364
|
-
const parsed = Number(envValue);
|
|
365
|
-
return Number.isFinite(parsed) && parsed > 0;
|
|
366
|
-
}
|
|
367
|
-
function isLikelyCommitmentRace(msg) {
|
|
368
|
-
return /CommitmentTooNew/i.test(msg) || /Revive\.ContractReverted/i.test(msg);
|
|
369
|
-
}
|
|
370
324
|
function classifyDotnsLabel(label) {
|
|
371
325
|
const totalLength = label.length;
|
|
372
326
|
const trailingDigits = countTrailingDigits(label);
|
|
@@ -400,6 +354,10 @@ function canRegister(requiredStatus, userStatus, trailingDigits) {
|
|
|
400
354
|
}
|
|
401
355
|
return trailingDigits !== 0 && userStatus !== ProofOfPersonhoodStatus.ProofOfPersonhoodLite;
|
|
402
356
|
}
|
|
357
|
+
function exampleNoStatusLabel(label) {
|
|
358
|
+
const base = stripTrailingDigits(validateDomainLabel(label)).replace(/[^a-z0-9-]/g, "x");
|
|
359
|
+
return `${base.padEnd(9, "x").slice(0, 9)}00.dot`;
|
|
360
|
+
}
|
|
403
361
|
function simulateUserStatus(currentStatus, requiredStatus, options) {
|
|
404
362
|
const canSelfAttest = options.canSelfAttest ?? true;
|
|
405
363
|
const max = (a, b) => a > b ? a : b;
|
|
@@ -440,6 +398,16 @@ function parseProofOfPersonhoodStatus(status) {
|
|
|
440
398
|
function popStatusName(status) {
|
|
441
399
|
return Object.keys(ProofOfPersonhoodStatus).find((k) => ProofOfPersonhoodStatus[k] === status) ?? String(status);
|
|
442
400
|
}
|
|
401
|
+
function normalizeProofOfPersonhoodStatus(status) {
|
|
402
|
+
if (typeof status === "number") return status;
|
|
403
|
+
if (typeof status === "bigint") return Number(status);
|
|
404
|
+
if (typeof status === "string") return Number(status);
|
|
405
|
+
throw new Error(`Unexpected ProofOfPersonhoodStatus type: ${typeof status}`);
|
|
406
|
+
}
|
|
407
|
+
function parsePersonhoodStatusResult(result) {
|
|
408
|
+
const status = Array.isArray(result) ? result[0]?.status ?? result[0] : result?.status;
|
|
409
|
+
return normalizeProofOfPersonhoodStatus(status);
|
|
410
|
+
}
|
|
443
411
|
var ReviveClientWrapper = class _ReviveClientWrapper {
|
|
444
412
|
static DRY_RUN_STORAGE_LIMIT = 18446744073709551615n;
|
|
445
413
|
static DRY_RUN_WEIGHT_LIMIT = { ref_time: 18446744073709551615n, proof_size: 18446744073709551615n };
|
|
@@ -608,7 +576,7 @@ var ReviveClientWrapper = class _ReviveClientWrapper {
|
|
|
608
576
|
}
|
|
609
577
|
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
610
578
|
}
|
|
611
|
-
async submitTransaction(contractAddress, value, encodedData, signerSubstrateAddress, signer, statusCallback, { rpcs, useNoncePolling, functionName, args }) {
|
|
579
|
+
async submitTransaction(contractAddress, value, encodedData, signerSubstrateAddress, signer, statusCallback, { rpcs, useNoncePolling, functionName, args, contracts }) {
|
|
612
580
|
await this.ensureAccountMapped(signerSubstrateAddress, signer);
|
|
613
581
|
const signerEvmAddress = await this.getEvmAddress(signerSubstrateAddress);
|
|
614
582
|
const gasEstimate = await this.estimateGasForCall(signerSubstrateAddress, contractAddress, value, encodedData);
|
|
@@ -620,7 +588,8 @@ var ReviveClientWrapper = class _ReviveClientWrapper {
|
|
|
620
588
|
signerEvmAddress,
|
|
621
589
|
value,
|
|
622
590
|
encodedData,
|
|
623
|
-
args
|
|
591
|
+
args,
|
|
592
|
+
contracts
|
|
624
593
|
}));
|
|
625
594
|
}
|
|
626
595
|
const weightLimit = { proof_size: gasEstimate.gasRequired.proofSize, ref_time: gasEstimate.gasRequired.referenceTime };
|
|
@@ -639,69 +608,6 @@ var ReviveClientWrapper = class _ReviveClientWrapper {
|
|
|
639
608
|
return await this.signAndSubmitWithRetry(buildExtrinsic, signer, statusCallback, "Revive.call", { nonceFallback });
|
|
640
609
|
}
|
|
641
610
|
};
|
|
642
|
-
async function runDotnsCli(argv, env) {
|
|
643
|
-
return new Promise((resolve, reject) => {
|
|
644
|
-
const cli = resolveDotnsCliInvocation();
|
|
645
|
-
try {
|
|
646
|
-
setDeployAttribute("deploy.dotns_cli.version", cli.version);
|
|
647
|
-
setDeployAttribute("deploy.dotns_cli.source", cli.source);
|
|
648
|
-
} catch {
|
|
649
|
-
}
|
|
650
|
-
const proc = spawn(cli.command, [...cli.argsPrefix, ...argv], {
|
|
651
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
652
|
-
env: { ...process.env, ...env }
|
|
653
|
-
});
|
|
654
|
-
let stdout = "";
|
|
655
|
-
let stderr = "";
|
|
656
|
-
proc.stdout.on("data", (chunk) => {
|
|
657
|
-
stdout += chunk.toString();
|
|
658
|
-
});
|
|
659
|
-
proc.stderr.on("data", (chunk) => {
|
|
660
|
-
stderr += chunk.toString();
|
|
661
|
-
});
|
|
662
|
-
proc.on("close", (code) => {
|
|
663
|
-
const out = stdout.trim();
|
|
664
|
-
const err = stderr.trim();
|
|
665
|
-
if (code === 0) {
|
|
666
|
-
if (!out) {
|
|
667
|
-
resolve({});
|
|
668
|
-
return;
|
|
669
|
-
}
|
|
670
|
-
try {
|
|
671
|
-
resolve(JSON.parse(out));
|
|
672
|
-
} catch {
|
|
673
|
-
resolve({ raw: out });
|
|
674
|
-
}
|
|
675
|
-
return;
|
|
676
|
-
}
|
|
677
|
-
let errorMsg = `dotns ${argv[0] ?? ""} failed (exit ${code})`;
|
|
678
|
-
if (err) {
|
|
679
|
-
try {
|
|
680
|
-
const parsed = JSON.parse(err);
|
|
681
|
-
if (parsed?.error) errorMsg = parsed.error;
|
|
682
|
-
} catch {
|
|
683
|
-
errorMsg = err.slice(0, 500) || errorMsg;
|
|
684
|
-
}
|
|
685
|
-
} else if (out) {
|
|
686
|
-
errorMsg = out.slice(0, 500);
|
|
687
|
-
}
|
|
688
|
-
reject(new Error(withDotnsCliFailureHint(errorMsg, cli)));
|
|
689
|
-
});
|
|
690
|
-
proc.on("error", (err) => reject(new Error(withDotnsCliFailureHint(`Failed to spawn DotNS CLI via ${describeDotnsCliInvocation(cli)}: ${err.message}`, cli))));
|
|
691
|
-
});
|
|
692
|
-
}
|
|
693
|
-
function buildAuthEnv(opts) {
|
|
694
|
-
const env = {};
|
|
695
|
-
if (opts.keyUri) {
|
|
696
|
-
env.DOTNS_KEY_URI = opts.keyUri;
|
|
697
|
-
} else if (opts.mnemonic) {
|
|
698
|
-
env.DOTNS_MNEMONIC = opts.mnemonic;
|
|
699
|
-
}
|
|
700
|
-
return env;
|
|
701
|
-
}
|
|
702
|
-
function rpcFlag(rpc) {
|
|
703
|
-
return rpc ? ["--rpc", rpc] : [];
|
|
704
|
-
}
|
|
705
611
|
var DotNS = class {
|
|
706
612
|
client;
|
|
707
613
|
clientWrapper;
|
|
@@ -714,21 +620,9 @@ var DotNS = class {
|
|
|
714
620
|
// bulletin-deploy resolves the asset-hub list via environments.json; falls
|
|
715
621
|
// back to the legacy paseo-only RPC_ENDPOINTS for direct library callers.
|
|
716
622
|
assetHubEndpoints;
|
|
717
|
-
// Stored credentials for CLI subprocess calls. Never logged or exposed.
|
|
718
|
-
_mnemonic = null;
|
|
719
|
-
_keyUri = null;
|
|
720
623
|
_usesExternalSigner = false;
|
|
721
|
-
_skipDotnsCli = false;
|
|
722
624
|
_contracts = CONTRACTS;
|
|
723
625
|
_nativeToEthRatio = NATIVE_TO_ETH_RATIO;
|
|
724
|
-
_dotnsSelfAttest = true;
|
|
725
|
-
// True when we must use direct contract calls instead of dotns-cli.
|
|
726
|
-
// Either an external signer was provided, or --skip-dotns-cli was set
|
|
727
|
-
// (needed for environments with custom contract addresses that dotns-cli
|
|
728
|
-
// does not support).
|
|
729
|
-
get _useContractPath() {
|
|
730
|
-
return this._usesExternalSigner || this._skipDotnsCli;
|
|
731
|
-
}
|
|
732
626
|
constructor() {
|
|
733
627
|
this.client = null;
|
|
734
628
|
this.clientWrapper = null;
|
|
@@ -749,29 +643,20 @@ var DotNS = class {
|
|
|
749
643
|
const rpc = options.rpc || process.env.DOTNS_RPC || this.assetHubEndpoints[0];
|
|
750
644
|
this.rpc = rpc;
|
|
751
645
|
this._usesExternalSigner = Boolean(options.signer && options.signerAddress);
|
|
752
|
-
this._skipDotnsCli = options.skipDotnsCli ?? false;
|
|
753
|
-
this._dotnsSelfAttest = options.dotnsSelfAttest ?? true;
|
|
754
|
-
let authEnv = {};
|
|
755
646
|
if (this._usesExternalSigner) {
|
|
756
|
-
this._keyUri = null;
|
|
757
|
-
this._mnemonic = null;
|
|
758
647
|
this.signer = options.signer;
|
|
759
648
|
this.substrateAddress = options.signerAddress;
|
|
760
649
|
} else {
|
|
761
650
|
const mnemonicArg = options.mnemonic || process.env.DOTNS_MNEMONIC || process.env.MNEMONIC;
|
|
762
651
|
const keyUriArg = options.keyUri || process.env.DOTNS_KEY_URI;
|
|
763
|
-
|
|
652
|
+
let source = keyUriArg || mnemonicArg || DEFAULT_MNEMONIC;
|
|
764
653
|
const isKeyUri = Boolean(keyUriArg);
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
if (options.derivationPath && !isKeyUri && this._mnemonic) {
|
|
768
|
-
this._keyUri = `${this._mnemonic}${options.derivationPath}`;
|
|
769
|
-
this._mnemonic = null;
|
|
654
|
+
if (options.derivationPath && !isKeyUri && source) {
|
|
655
|
+
source = `${source}${options.derivationPath}`;
|
|
770
656
|
}
|
|
771
|
-
authEnv = buildAuthEnv({ mnemonic: this._mnemonic ?? void 0, keyUri: this._keyUri ?? void 0 });
|
|
772
657
|
await cryptoWaitReady();
|
|
773
658
|
const keyring = new Keyring({ type: "sr25519" });
|
|
774
|
-
const account =
|
|
659
|
+
const account = isKeyUri || options.derivationPath ? keyring.addFromUri(source) : keyring.addFromMnemonic(source);
|
|
775
660
|
this.signer = getPolkadotSigner(account.publicKey, "Sr25519", async (input) => account.sign(input));
|
|
776
661
|
this.substrateAddress = account.address;
|
|
777
662
|
}
|
|
@@ -792,48 +677,50 @@ var DotNS = class {
|
|
|
792
677
|
this.connected = true;
|
|
793
678
|
if (options.nativeToEthRatio) this._nativeToEthRatio = options.nativeToEthRatio;
|
|
794
679
|
try {
|
|
795
|
-
|
|
796
|
-
await this.ensureAutoMappedAccountReady();
|
|
797
|
-
} else {
|
|
798
|
-
if (!await this.clientWrapper.checkIfAccountMapped(this.substrateAddress)) {
|
|
799
|
-
console.log(` Mapping account on Asset Hub Revive...`);
|
|
800
|
-
if (this._usesExternalSigner) {
|
|
801
|
-
await this.clientWrapper.ensureAccountMapped(this.substrateAddress, this.signer);
|
|
802
|
-
} else {
|
|
803
|
-
try {
|
|
804
|
-
await runDotnsCli(["account", "map", ...rpcFlag(rpc)], authEnv);
|
|
805
|
-
} catch (e) {
|
|
806
|
-
captureWarning("account map failed during connect (will rely on chain confirmation)", { error: e.message?.slice(0, 200) });
|
|
807
|
-
}
|
|
808
|
-
const mappingDeadline = Date.now() + 15e3;
|
|
809
|
-
let mappingConfirmed = false;
|
|
810
|
-
while (Date.now() < mappingDeadline) {
|
|
811
|
-
if (await this.clientWrapper.checkIfAccountMapped(this.substrateAddress)) {
|
|
812
|
-
mappingConfirmed = true;
|
|
813
|
-
break;
|
|
814
|
-
}
|
|
815
|
-
await new Promise((r) => setTimeout(r, 1500));
|
|
816
|
-
}
|
|
817
|
-
if (!mappingConfirmed) {
|
|
818
|
-
throw new Error(`Account mapping did not take effect on-chain for ${this.substrateAddress}. The map_account tx may have been dropped or hit a dispatch error \u2014 check the signer's balance for existential deposit + fees.`);
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
console.log(` Account: mapped`);
|
|
823
|
-
}
|
|
680
|
+
await this.ensureMappedAccountReady(options.autoAccountMapping ?? false);
|
|
824
681
|
} catch (e) {
|
|
825
682
|
this.connected = false;
|
|
826
683
|
throw e;
|
|
827
684
|
}
|
|
828
685
|
return this;
|
|
829
686
|
}
|
|
687
|
+
async ensureMappedAccountReady(autoAccountMapping = false) {
|
|
688
|
+
this.ensureConnected();
|
|
689
|
+
if (!this.clientWrapper || !this.substrateAddress || !this.signer) {
|
|
690
|
+
throw new Error("Account mapping unavailable before DotNS signer is initialized");
|
|
691
|
+
}
|
|
692
|
+
if (autoAccountMapping) {
|
|
693
|
+
await this.ensureAutoMappedAccountReady();
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
if (await this.clientWrapper.checkIfAccountMapped(this.substrateAddress)) {
|
|
697
|
+
console.log(` Account: mapped`);
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
console.log(` Mapping account on Asset Hub Revive...`);
|
|
701
|
+
try {
|
|
702
|
+
await this.clientWrapper.ensureAccountMapped(this.substrateAddress, this.signer);
|
|
703
|
+
} catch (e) {
|
|
704
|
+
if (await this.clientWrapper.checkIfAccountMapped(this.substrateAddress)) {
|
|
705
|
+
console.log(` Account: mapped`);
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
captureWarning("explicit account mapping failed; falling back to Revive auto-map trigger", {
|
|
709
|
+
signer: this.substrateAddress,
|
|
710
|
+
error: e?.message?.slice?.(0, 200) ?? String(e).slice(0, 200)
|
|
711
|
+
});
|
|
712
|
+
await this.ensureAutoMappedAccountReady();
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
console.log(` Account: mapped`);
|
|
716
|
+
}
|
|
830
717
|
async ensureAutoMappedAccountReady() {
|
|
831
718
|
this.ensureConnected();
|
|
832
719
|
if (!this.clientWrapper || !this.substrateAddress || !this.signer) {
|
|
833
720
|
throw new Error("Account auto-mapping unavailable before DotNS signer is initialized");
|
|
834
721
|
}
|
|
835
722
|
if (await this.clientWrapper.checkIfAccountMapped(this.substrateAddress)) {
|
|
836
|
-
console.log(` Account: auto-mapped`);
|
|
723
|
+
console.log(` Account: auto-mapped (Revive.OriginalAccount confirmed)`);
|
|
837
724
|
return;
|
|
838
725
|
}
|
|
839
726
|
if (await this.isTestnet()) {
|
|
@@ -875,7 +762,7 @@ var DotNS = class {
|
|
|
875
762
|
if (!await this.clientWrapper.checkIfAccountMapped(this.substrateAddress)) {
|
|
876
763
|
throw new Error(`Account auto-mapping did not take effect on-chain for ${this.substrateAddress}. The signer needs enough testnet PAS to submit the Revive auto-map trigger before DotNS preflight can run. Top up at ${PASEO_FAUCET_URL} or fund Alice/Bob so auto-top-up can help.`);
|
|
877
764
|
}
|
|
878
|
-
console.log(` Account: auto-mapped`);
|
|
765
|
+
console.log(` Account: auto-mapped (Revive.OriginalAccount confirmed)`);
|
|
879
766
|
}
|
|
880
767
|
ensureConnected() {
|
|
881
768
|
if (!this.connected) throw new Error("Not connected. Call connect() first.");
|
|
@@ -1044,7 +931,8 @@ var DotNS = class {
|
|
|
1044
931
|
signerEvmAddress: this.evmAddress ?? void 0,
|
|
1045
932
|
value: 0n,
|
|
1046
933
|
encodedData: encodedCallData,
|
|
1047
|
-
args
|
|
934
|
+
args,
|
|
935
|
+
contracts: this._contracts
|
|
1048
936
|
}));
|
|
1049
937
|
}
|
|
1050
938
|
return decodeFunctionResult({ abi: contractAbi, functionName, data: callResult.result.value.data });
|
|
@@ -1056,7 +944,7 @@ var DotNS = class {
|
|
|
1056
944
|
const encodedCallData = encodeFunctionData({ abi: contractAbi, functionName, args });
|
|
1057
945
|
const rpcs = this.rpc ? [this.rpc, ...this.assetHubEndpoints.filter((ep) => ep !== this.rpc)] : this.assetHubEndpoints;
|
|
1058
946
|
return await withTimeout(
|
|
1059
|
-
this.clientWrapper.submitTransaction(contractAddress, value, encodedCallData, this.substrateAddress, this.signer, statusCallback, { rpcs, useNoncePolling, functionName, args }),
|
|
947
|
+
this.clientWrapper.submitTransaction(contractAddress, value, encodedCallData, this.substrateAddress, this.signer, statusCallback, { rpcs, useNoncePolling, functionName, args, contracts: this._contracts }),
|
|
1060
948
|
OPERATION_TIMEOUT_MS,
|
|
1061
949
|
functionName
|
|
1062
950
|
);
|
|
@@ -1064,22 +952,9 @@ var DotNS = class {
|
|
|
1064
952
|
async checkOwnership(label, ownerAddress = null) {
|
|
1065
953
|
this.ensureConnected();
|
|
1066
954
|
const checkAddress = (ownerAddress || this.evmAddress).toLowerCase();
|
|
1067
|
-
|
|
1068
|
-
const tokenId = computeDomainTokenId(label);
|
|
1069
|
-
try {
|
|
1070
|
-
const owner = await withTimeout(this.contractCall(this._contracts.DOTNS_REGISTRAR, DOTNS_REGISTRAR_ABI, "ownerOf", [tokenId]), 3e4, "ownerOf");
|
|
1071
|
-
const owned = owner.toLowerCase() === checkAddress;
|
|
1072
|
-
return { owned, owner };
|
|
1073
|
-
} catch {
|
|
1074
|
-
return { owned: false, owner: null };
|
|
1075
|
-
}
|
|
1076
|
-
}
|
|
955
|
+
const tokenId = computeDomainTokenId(label);
|
|
1077
956
|
try {
|
|
1078
|
-
const
|
|
1079
|
-
["lookup", "owner-of", label, "--json", ...rpcFlag(this.rpc)]
|
|
1080
|
-
);
|
|
1081
|
-
if (!result.registered) return { owned: false, owner: null };
|
|
1082
|
-
const owner = result.ownerEvm;
|
|
957
|
+
const owner = await withTimeout(this.contractCall(this._contracts.DOTNS_REGISTRAR, DOTNS_REGISTRAR_ABI, "ownerOf", [tokenId]), 3e4, "ownerOf");
|
|
1083
958
|
const owned = owner.toLowerCase() === checkAddress;
|
|
1084
959
|
return { owned, owner };
|
|
1085
960
|
} catch {
|
|
@@ -1089,56 +964,21 @@ var DotNS = class {
|
|
|
1089
964
|
async getUserPopStatus(ownerAddress = null) {
|
|
1090
965
|
this.ensureConnected();
|
|
1091
966
|
const checkAddress = ownerAddress || this.evmAddress;
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
return 0;
|
|
967
|
+
try {
|
|
968
|
+
const result = await withTimeout(
|
|
969
|
+
this.contractCall(PERSONHOOD_PRECOMPILE_ADDRESS, PERSONHOOD_ABI, "personhoodStatus", [checkAddress, PERSONHOOD_CONTEXT]),
|
|
970
|
+
3e4,
|
|
971
|
+
"personhoodStatus"
|
|
972
|
+
);
|
|
973
|
+
return parsePersonhoodStatusResult(result);
|
|
974
|
+
} catch (e) {
|
|
975
|
+
throw new Error(
|
|
976
|
+
`Could not read DotNS Personhood status for ${checkAddress} from the Personhood precompile. Check the Asset Hub RPC/environment and contact the DotNS team if the signer should be whitelisted. Underlying: ${e?.message ?? String(e)}`
|
|
977
|
+
);
|
|
1104
978
|
}
|
|
1105
|
-
const authEnv = buildAuthEnv({ mnemonic: this._mnemonic ?? void 0, keyUri: this._keyUri ?? void 0 });
|
|
1106
|
-
const info = await runDotnsCli(
|
|
1107
|
-
["pop", "info", "--json", ...rpcFlag(this.rpc)],
|
|
1108
|
-
authEnv
|
|
1109
|
-
);
|
|
1110
|
-
return info.statusCode ?? 0;
|
|
1111
979
|
}
|
|
1112
|
-
async setUserPopStatus(
|
|
1113
|
-
|
|
1114
|
-
console.log(`
|
|
1115
|
-
Checking current PoP status...`);
|
|
1116
|
-
const currentStatus = await this.getUserPopStatus();
|
|
1117
|
-
const currentStatusName = popStatusName(currentStatus);
|
|
1118
|
-
const desiredStatusName = popStatusName(status);
|
|
1119
|
-
console.log(` Current: ${currentStatusName}`);
|
|
1120
|
-
console.log(` Desired: ${desiredStatusName}`);
|
|
1121
|
-
if (currentStatus === status) {
|
|
1122
|
-
console.log(` Status already set, skipping update`);
|
|
1123
|
-
return;
|
|
1124
|
-
}
|
|
1125
|
-
if (currentStatus > status) {
|
|
1126
|
-
console.log(` Current status already satisfies desired, skipping downgrade`);
|
|
1127
|
-
return;
|
|
1128
|
-
}
|
|
1129
|
-
console.log(` Setting PoP status to ${desiredStatusName}...`);
|
|
1130
|
-
if (this._useContractPath) {
|
|
1131
|
-
const txHash = await this.contractTransaction(this._contracts.POP_RULES, 0n, POP_RULES_ABI, "setUserPopStatus", [status], (s) => console.log(` ${s}`));
|
|
1132
|
-
console.log(` Tx: ${txHash}`);
|
|
1133
|
-
return;
|
|
1134
|
-
}
|
|
1135
|
-
const statusStr = desiredStatusName.replace("ProofOfPersonhood", "").toLowerCase() || "none";
|
|
1136
|
-
const authEnv = buildAuthEnv({ mnemonic: this._mnemonic ?? void 0, keyUri: this._keyUri ?? void 0 });
|
|
1137
|
-
const result = await runDotnsCli(
|
|
1138
|
-
["pop", "set", statusStr, "--json", ...rpcFlag(this.rpc)],
|
|
1139
|
-
authEnv
|
|
1140
|
-
);
|
|
1141
|
-
console.log(` PoP status set: ${result.statusCode}`);
|
|
980
|
+
async setUserPopStatus(_status) {
|
|
981
|
+
throw new Error("DotNS self-attestation is no longer available. Personhood status is read from the Personhood precompile; contact the DotNS team for whitelisting / status changes.");
|
|
1142
982
|
}
|
|
1143
983
|
async checkSubdomainOwnership(sublabel, parentLabel) {
|
|
1144
984
|
this.ensureConnected();
|
|
@@ -1158,25 +998,16 @@ var DotNS = class {
|
|
|
1158
998
|
this.ensureConnected();
|
|
1159
999
|
console.log(`
|
|
1160
1000
|
Registering subdomain ${sublabel}.${parentLabel}.dot...`);
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
return { sublabel, parentLabel, owner: this.evmAddress };
|
|
1172
|
-
}
|
|
1173
|
-
const authEnv = buildAuthEnv({ mnemonic: this._mnemonic ?? void 0, keyUri: this._keyUri ?? void 0 });
|
|
1174
|
-
const result = await runDotnsCli(
|
|
1175
|
-
["register", "subname", "-n", sublabel, "-p", parentLabel, "--json", ...rpcFlag(this.rpc)],
|
|
1176
|
-
authEnv
|
|
1177
|
-
);
|
|
1178
|
-
console.log(` Subdomain registered: ${result.domain}`);
|
|
1179
|
-
return { sublabel, parentLabel, owner: result.owner ?? this.evmAddress };
|
|
1001
|
+
const parentNode = namehash(`${parentLabel}.dot`);
|
|
1002
|
+
const subnodeRecord = { parentNode, subLabel: sublabel, parentLabel, owner: this.evmAddress };
|
|
1003
|
+
const txHash = await this.contractTransaction(this._contracts.DOTNS_REGISTRY, 0n, DOTNS_REGISTRY_ABI, "setSubnodeOwner", [subnodeRecord], (s) => console.log(` ${s}`), { useNoncePolling: true });
|
|
1004
|
+
console.log(` Tx: ${txHash}`);
|
|
1005
|
+
console.log(` Setting resolver...`);
|
|
1006
|
+
const subnodeNode = namehash(`${sublabel}.${parentLabel}.dot`);
|
|
1007
|
+
const resolverTxHash = await this.contractTransaction(this._contracts.DOTNS_REGISTRY, 0n, DOTNS_REGISTRY_ABI, "setResolver", [subnodeNode, this._contracts.DOTNS_CONTENT_RESOLVER], (s) => console.log(` ${s}`), { useNoncePolling: true });
|
|
1008
|
+
console.log(` Tx: ${resolverTxHash}`);
|
|
1009
|
+
console.log(` Subdomain registered!`);
|
|
1010
|
+
return { sublabel, parentLabel, owner: this.evmAddress };
|
|
1180
1011
|
});
|
|
1181
1012
|
}
|
|
1182
1013
|
async setContenthash(domainName, contenthashHex) {
|
|
@@ -1193,45 +1024,25 @@ var DotNS = class {
|
|
|
1193
1024
|
}
|
|
1194
1025
|
if (!ipfsCid) throw new Error(`setContenthash: cannot decode contenthash ${contenthashHex} to an IPFS CID`);
|
|
1195
1026
|
console.log(` Setting contenthash: ${ipfsCid}`);
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
1212
|
-
}
|
|
1213
|
-
if (onChain !== expected) {
|
|
1214
|
-
throw new Error(
|
|
1215
|
-
`Post-deploy verification failed for ${domainName}.dot: on-chain contenthash is ${onChain}, not the ${expected} we just wrote. The setContenthash tx may have silently failed, or another party overwrote the domain. Re-run the deploy to retry.`
|
|
1216
|
-
);
|
|
1217
|
-
}
|
|
1218
|
-
console.log(` Verified on-chain: ${ipfsCid}
|
|
1219
|
-
`);
|
|
1220
|
-
return { node };
|
|
1027
|
+
const txHash = await this.contractTransaction(this._contracts.DOTNS_CONTENT_RESOLVER, 0n, DOTNS_CONTENT_RESOLVER_ABI, "setContenthash", [node, contenthashHex], (s) => console.log(` ${s}`), { useNoncePolling: true });
|
|
1028
|
+
console.log(` Tx: ${txHash}`);
|
|
1029
|
+
const expected = contenthashHex.toLowerCase();
|
|
1030
|
+
const MAX_CHAIN_WAIT_SECONDS = 90;
|
|
1031
|
+
const POLL_INTERVAL_MS = 2e3;
|
|
1032
|
+
const startChainMs = Number(await this.clientWrapper.client.query.Timestamp.Now.getValue());
|
|
1033
|
+
let onChain = "0x";
|
|
1034
|
+
while (true) {
|
|
1035
|
+
onChain = (await this.getContenthash(domainName) || "0x").toLowerCase();
|
|
1036
|
+
if (onChain === expected) break;
|
|
1037
|
+
const nowChainMs = Number(await this.clientWrapper.client.query.Timestamp.Now.getValue());
|
|
1038
|
+
const chainElapsed = (nowChainMs - startChainMs) / 1e3;
|
|
1039
|
+
if (chainElapsed >= MAX_CHAIN_WAIT_SECONDS) break;
|
|
1040
|
+
console.log(` Awaiting finalization (chain time +${Math.floor(chainElapsed)}s / ${MAX_CHAIN_WAIT_SECONDS}s)...`);
|
|
1041
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
1221
1042
|
}
|
|
1222
|
-
|
|
1223
|
-
const setResult = await runDotnsCli(
|
|
1224
|
-
["content", "set", domainName, ipfsCid, "--json", ...rpcFlag(this.rpc)],
|
|
1225
|
-
authEnv
|
|
1226
|
-
);
|
|
1227
|
-
console.log(` Tx: ${setResult.txHash}`);
|
|
1228
|
-
const viewResult = await runDotnsCli(
|
|
1229
|
-
["content", "view", domainName, "--json", ...rpcFlag(this.rpc)]
|
|
1230
|
-
);
|
|
1231
|
-
const onChainCid = viewResult.cid;
|
|
1232
|
-
if (!onChainCid || onChainCid !== ipfsCid) {
|
|
1043
|
+
if (onChain !== expected) {
|
|
1233
1044
|
throw new Error(
|
|
1234
|
-
`Post-deploy verification failed for ${domainName}.dot: on-chain
|
|
1045
|
+
`Post-deploy verification failed for ${domainName}.dot: on-chain contenthash is ${onChain}, not the ${expected} we just wrote. The setContenthash tx may have silently failed, or another party overwrote the domain. Re-run the deploy to retry.`
|
|
1235
1046
|
);
|
|
1236
1047
|
}
|
|
1237
1048
|
console.log(` Verified on-chain: ${ipfsCid}
|
|
@@ -1239,66 +1050,49 @@ var DotNS = class {
|
|
|
1239
1050
|
return { node };
|
|
1240
1051
|
});
|
|
1241
1052
|
}
|
|
1242
|
-
async setTextRecord(domainName, key, value
|
|
1053
|
+
async setTextRecord(domainName, key, value) {
|
|
1243
1054
|
return withSpan("deploy.dotns.set-text", `2c. set-text ${key}`, {}, async () => {
|
|
1244
1055
|
this.ensureConnected();
|
|
1245
1056
|
console.log(` Setting text[${key}]: ${value}`);
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1057
|
+
const node = namehash(`${domainName}.dot`);
|
|
1058
|
+
const txHash = await this.contractTransaction(this._contracts.DOTNS_RESOLVER, 0n, DOTNS_TEXT_RESOLVER_ABI, "setText", [node, key, value], (s) => console.log(` ${s}`), { useNoncePolling: true });
|
|
1059
|
+
console.log(` Tx: ${txHash}`);
|
|
1060
|
+
const MAX_CHAIN_WAIT_SECONDS = 90;
|
|
1061
|
+
const POLL_INTERVAL_MS = 2e3;
|
|
1062
|
+
const startChainMs = Number(await this.clientWrapper.client.query.Timestamp.Now.getValue());
|
|
1063
|
+
let onChainValue = "";
|
|
1064
|
+
while (true) {
|
|
1065
|
+
const onChain = await withTimeout(this.contractCall(this._contracts.DOTNS_RESOLVER, DOTNS_TEXT_RESOLVER_ABI, "text", [node, key]), 3e4, "text");
|
|
1066
|
+
onChainValue = onChain ?? "";
|
|
1067
|
+
if (onChainValue === value) break;
|
|
1068
|
+
const nowChainMs = Number(await this.clientWrapper.client.query.Timestamp.Now.getValue());
|
|
1069
|
+
const chainElapsed = (nowChainMs - startChainMs) / 1e3;
|
|
1070
|
+
if (chainElapsed >= MAX_CHAIN_WAIT_SECONDS) break;
|
|
1071
|
+
console.log(` Awaiting text finalization (chain time +${Math.floor(chainElapsed)}s / ${MAX_CHAIN_WAIT_SECONDS}s)...`);
|
|
1072
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
|
|
1259
1073
|
}
|
|
1260
|
-
|
|
1261
|
-
const setResult = await _cli(
|
|
1262
|
-
["text", "set", domainName, key, value, "--json", ...rpcFlag(this.rpc)],
|
|
1263
|
-
authEnv
|
|
1264
|
-
);
|
|
1265
|
-
console.log(` Tx: ${setResult.txHash}`);
|
|
1266
|
-
const viewResult = await _cli(
|
|
1267
|
-
["text", "view", domainName, key, "--json", ...rpcFlag(this.rpc)]
|
|
1268
|
-
);
|
|
1269
|
-
const onChain = viewResult.value ?? "";
|
|
1270
|
-
if (onChain !== value) {
|
|
1074
|
+
if (onChainValue !== value) {
|
|
1271
1075
|
throw new Error(
|
|
1272
|
-
`Post-set verification failed for text[${key}] on ${domainName}.dot: on-chain value is ${JSON.stringify(
|
|
1076
|
+
`Post-set verification failed for text[${key}] on ${domainName}.dot: on-chain value is ${JSON.stringify(onChainValue)}, not ${JSON.stringify(value)} we just wrote. The setText tx may have silently failed, or another writer overwrote the record.`
|
|
1273
1077
|
);
|
|
1274
1078
|
}
|
|
1275
|
-
console.log(` Verified text[${key}]: ${
|
|
1079
|
+
console.log(` Verified text[${key}]: ${onChainValue}
|
|
1276
1080
|
`);
|
|
1277
|
-
return { value, txHash
|
|
1081
|
+
return { value, txHash };
|
|
1278
1082
|
});
|
|
1279
1083
|
}
|
|
1280
1084
|
async getContenthash(domainName) {
|
|
1281
1085
|
this.ensureConnected();
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
"contenthash"
|
|
1288
|
-
);
|
|
1289
|
-
return typeof result2 === "string" ? result2 : result2?.toString?.() ?? String(result2);
|
|
1290
|
-
}
|
|
1291
|
-
const result = await runDotnsCli(
|
|
1292
|
-
["content", "view", domainName, "--json", ...rpcFlag(this.rpc)]
|
|
1086
|
+
const node = namehash(`${domainName}.dot`);
|
|
1087
|
+
const result = await withTimeout(
|
|
1088
|
+
this.contractCall(this._contracts.DOTNS_CONTENT_RESOLVER, DOTNS_CONTENT_RESOLVER_ABI, "contenthash", [node]),
|
|
1089
|
+
3e4,
|
|
1090
|
+
"contenthash"
|
|
1293
1091
|
);
|
|
1294
|
-
return result
|
|
1092
|
+
return typeof result === "string" ? result : result?.toString?.() ?? String(result);
|
|
1295
1093
|
}
|
|
1296
1094
|
async classifyName(label) {
|
|
1297
1095
|
this.ensureConnected();
|
|
1298
|
-
if (!this._useContractPath) {
|
|
1299
|
-
const classification = classifyDotnsLabel(label);
|
|
1300
|
-
return { requiredStatus: classification.status, message: classification.message };
|
|
1301
|
-
}
|
|
1302
1096
|
console.log(`
|
|
1303
1097
|
Classifying name via PopOracle...`);
|
|
1304
1098
|
const result = await withTimeout(this.contractCall(this._contracts.POP_RULES, POP_RULES_ABI, "classifyName", [label]), 3e4, "classifyName");
|
|
@@ -1432,7 +1226,7 @@ var DotNS = class {
|
|
|
1432
1226
|
// View-only readiness check. Runs every chain read needed to predict whether
|
|
1433
1227
|
// `register(label)` will succeed, so the caller can fail-fast BEFORE the
|
|
1434
1228
|
// Bulletin chunk upload. Never writes to chain. See issue #100.
|
|
1435
|
-
async preflight(label
|
|
1229
|
+
async preflight(label) {
|
|
1436
1230
|
return withSpan("deploy.dotns.preflight", `preflight ${label}.dot`, {}, async () => {
|
|
1437
1231
|
this.ensureConnected();
|
|
1438
1232
|
const validated = validateDomainLabel(label);
|
|
@@ -1526,20 +1320,28 @@ var DotNS = class {
|
|
|
1526
1320
|
signerFreeBalance
|
|
1527
1321
|
};
|
|
1528
1322
|
}
|
|
1529
|
-
const
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1323
|
+
const targetPopStatus = userStatus;
|
|
1324
|
+
if (!canRegister(classification.status, userStatus, trailingDigits)) {
|
|
1325
|
+
if (classification.status === ProofOfPersonhoodStatus.NoStatus && userStatus === ProofOfPersonhoodStatus.ProofOfPersonhoodLite) {
|
|
1326
|
+
return {
|
|
1327
|
+
label: validated,
|
|
1328
|
+
classification,
|
|
1329
|
+
userStatus,
|
|
1330
|
+
trailingDigits,
|
|
1331
|
+
baselength,
|
|
1332
|
+
isAvailable: true,
|
|
1333
|
+
existingOwner: null,
|
|
1334
|
+
isBaseNameReserved: isReserved,
|
|
1335
|
+
reservationOwner,
|
|
1336
|
+
isTestnet,
|
|
1337
|
+
canProceed: false,
|
|
1338
|
+
reason: `${validated}.dot: this name class is NoStatus-compatible, but Personhood Lite signers cannot register NoStatus-class labels. Self-attestation is no longer available. Use a NoStatus or Full signer, or contact the DotNS team for whitelisting / Personhood status help.`,
|
|
1339
|
+
plannedAction: "abort",
|
|
1340
|
+
needsPopUpgrade: false,
|
|
1341
|
+
targetPopStatus,
|
|
1342
|
+
signerFreeBalance
|
|
1343
|
+
};
|
|
1344
|
+
}
|
|
1543
1345
|
const currentName = popStatusName(userStatus);
|
|
1544
1346
|
const requiredName = popStatusName(classification.status);
|
|
1545
1347
|
return {
|
|
@@ -1554,28 +1356,7 @@ var DotNS = class {
|
|
|
1554
1356
|
reservationOwner,
|
|
1555
1357
|
isTestnet,
|
|
1556
1358
|
canProceed: false,
|
|
1557
|
-
reason:
|
|
1558
|
-
plannedAction: "abort",
|
|
1559
|
-
needsPopUpgrade: false,
|
|
1560
|
-
targetPopStatus,
|
|
1561
|
-
signerFreeBalance
|
|
1562
|
-
};
|
|
1563
|
-
}
|
|
1564
|
-
if (!canRegister(classification.status, targetPopStatus, trailingDigits)) {
|
|
1565
|
-
const className = popStatusName(classification.status);
|
|
1566
|
-
return {
|
|
1567
|
-
label: validated,
|
|
1568
|
-
classification,
|
|
1569
|
-
userStatus,
|
|
1570
|
-
trailingDigits,
|
|
1571
|
-
baselength,
|
|
1572
|
-
isAvailable: true,
|
|
1573
|
-
existingOwner: null,
|
|
1574
|
-
isBaseNameReserved: isReserved,
|
|
1575
|
-
reservationOwner,
|
|
1576
|
-
isTestnet,
|
|
1577
|
-
canProceed: false,
|
|
1578
|
-
reason: `${validated}.dot classifies as ${className}; this signer cannot register it (PopRules.priceWithCheck gate). Remediations: use a signer with Full PoP, or pick a base name of 6-8 chars + trailing 00 (which classifies as PopLite).`,
|
|
1359
|
+
reason: `${validated}.dot requires ${requiredName}, but this signer is ${currentName}. Self-attestation is no longer available. Choose a NoStatus-compatible name (base length >= 9 with exactly two trailing digits, for example ${exampleNoStatusLabel(validated)}) or contact the DotNS team for whitelisting / Personhood status.`,
|
|
1579
1360
|
plannedAction: "abort",
|
|
1580
1361
|
needsPopUpgrade: false,
|
|
1581
1362
|
targetPopStatus,
|
|
@@ -1595,7 +1376,7 @@ var DotNS = class {
|
|
|
1595
1376
|
isTestnet,
|
|
1596
1377
|
canProceed: true,
|
|
1597
1378
|
plannedAction: "register",
|
|
1598
|
-
needsPopUpgrade:
|
|
1379
|
+
needsPopUpgrade: false,
|
|
1599
1380
|
targetPopStatus
|
|
1600
1381
|
}, signerFreeBalance, isTestnet);
|
|
1601
1382
|
});
|
|
@@ -1646,97 +1427,48 @@ var DotNS = class {
|
|
|
1646
1427
|
}
|
|
1647
1428
|
return { ...candidate, signerFreeBalance: effectiveBalance, feeFloor, toppedUp };
|
|
1648
1429
|
}
|
|
1649
|
-
async register(label, options = {}
|
|
1430
|
+
async register(label, options = {}) {
|
|
1650
1431
|
return withSpan("deploy.dotns.register", `2a. register ${label}.dot`, {}, async () => {
|
|
1651
1432
|
if (!this.connected) await this.connect(options);
|
|
1652
1433
|
label = validateDomainLabel(label);
|
|
1653
1434
|
const trailingDigitCount = countTrailingDigits(label);
|
|
1654
1435
|
const preClassification = classifyDotnsLabel(label);
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
throw new Error("Personhood Lite cannot register base names \u2014 this name class requires a Full or NoStatus signer");
|
|
1659
|
-
}
|
|
1436
|
+
const preRequiredStatus = preClassification.status;
|
|
1437
|
+
if (preRequiredStatus === ProofOfPersonhoodStatus.Reserved) {
|
|
1438
|
+
throw new Error(preClassification.message);
|
|
1660
1439
|
}
|
|
1661
|
-
const
|
|
1662
|
-
|
|
1663
|
-
if (this._useContractPath) {
|
|
1664
|
-
const [classification] = await Promise.all([
|
|
1665
|
-
this.classifyName(label),
|
|
1666
|
-
this.ensureNotRegistered(label)
|
|
1667
|
-
]);
|
|
1668
|
-
const requiredStatus = classification.requiredStatus;
|
|
1669
|
-
if (requiredStatus === ProofOfPersonhoodStatus.Reserved) {
|
|
1670
|
-
throw new Error(classification.message);
|
|
1671
|
-
}
|
|
1672
|
-
const initialUserStatus = await this.getUserPopStatus();
|
|
1673
|
-
const isTestnet = await this.isTestnet();
|
|
1674
|
-
const explicitStatusNum = explicitStatus ? parseProofOfPersonhoodStatus(explicitStatus) : void 0;
|
|
1675
|
-
const targetUserStatus = simulateUserStatus(initialUserStatus, requiredStatus, {
|
|
1676
|
-
explicitStatus: explicitStatusNum,
|
|
1677
|
-
isTestnet,
|
|
1678
|
-
canSelfAttest: this._dotnsSelfAttest
|
|
1679
|
-
});
|
|
1680
|
-
if (!canRegister(requiredStatus, targetUserStatus, countTrailingDigits(label))) {
|
|
1440
|
+
const rejectIneligible = (statusRequired, userStatus2) => {
|
|
1441
|
+
if (statusRequired === ProofOfPersonhoodStatus.NoStatus && userStatus2 === ProofOfPersonhoodStatus.ProofOfPersonhoodLite) {
|
|
1681
1442
|
throw new Error(
|
|
1682
|
-
|
|
1443
|
+
`${label}.dot: this name class is NoStatus-compatible, but Personhood Lite signers cannot register NoStatus-class labels. Self-attestation is no longer available. Use a NoStatus or Full signer, or contact the DotNS team for whitelisting / Personhood status help.`
|
|
1683
1444
|
);
|
|
1684
1445
|
}
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
const userStatus = await this.getUserPopStatus();
|
|
1688
|
-
if (userStatus !== targetUserStatus) {
|
|
1689
|
-
throw new Error(
|
|
1690
|
-
"setUserPopStatus did not land as expected (wanted " + targetUserStatus + ", got " + userStatus + "). Check RPC connectivity and POP_RULES contract."
|
|
1691
|
-
);
|
|
1692
|
-
}
|
|
1693
|
-
}
|
|
1694
|
-
const { commitment, registration } = await this.generateCommitment(label, reverse);
|
|
1695
|
-
await withSpan("deploy.dotns.submit-commitment", "2a-i. submit-commitment", {}, () => this.submitCommitment(commitment));
|
|
1696
|
-
await withSpan("deploy.dotns.wait-commitment-age", "2a-ii. wait-commitment-age", {}, () => this.waitForCommitmentAge(commitment));
|
|
1697
|
-
const pricing = await withSpan("deploy.dotns.price-validation", "2a-iii. price-validation", {}, () => this.getPriceAndValidate(label));
|
|
1698
|
-
await withSpan("deploy.dotns.finalize-registration", "2a-iv. finalize-registration", {}, () => this.finalizeRegistration(registration, pricing.priceWei));
|
|
1699
|
-
await this.verifyOwnership(label);
|
|
1700
|
-
console.log(`
|
|
1701
|
-
Registration complete!`);
|
|
1702
|
-
return { label, owner: this.evmAddress };
|
|
1703
|
-
}
|
|
1704
|
-
const statusArgs = explicitStatus ? ["-s", explicitStatus] : [];
|
|
1705
|
-
const reverseArgs = reverse ? ["-r"] : [];
|
|
1706
|
-
console.log(`
|
|
1707
|
-
Registering ${label}.dot via dotns CLI...`);
|
|
1708
|
-
const authEnv = buildAuthEnv({ mnemonic: this._mnemonic ?? void 0, keyUri: this._keyUri ?? void 0 });
|
|
1709
|
-
const userSetBuffer = isExplicitCommitmentBuffer(process.env.DOTNS_COMMITMENT_BUFFER);
|
|
1710
|
-
if (!userSetBuffer) {
|
|
1711
|
-
authEnv.DOTNS_COMMITMENT_BUFFER = "30";
|
|
1712
|
-
}
|
|
1713
|
-
const runRegister = async (bufferSeconds) => {
|
|
1714
|
-
const env = bufferSeconds ? { ...authEnv, DOTNS_COMMITMENT_BUFFER: bufferSeconds } : authEnv;
|
|
1715
|
-
return await _cli(
|
|
1716
|
-
["register", "domain", "-n", label, "--json", ...statusArgs, ...reverseArgs, ...rpcFlag(this.rpc)],
|
|
1717
|
-
env
|
|
1446
|
+
throw new Error(
|
|
1447
|
+
`${label}.dot requires ${popStatusName(statusRequired)}, but this signer is ${popStatusName(userStatus2)}. Self-attestation is no longer available. Choose a NoStatus-compatible name (base length >= 9 with exactly two trailing digits, for example ${exampleNoStatusLabel(label)}) or contact the DotNS team for whitelisting / Personhood status.`
|
|
1718
1448
|
);
|
|
1719
1449
|
};
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
try {
|
|
1729
|
-
result = await runRegister(retryBuffer);
|
|
1730
|
-
} catch (retryErr) {
|
|
1731
|
-
const retryMsg = retryErr.message;
|
|
1732
|
-
if (!isLikelyCommitmentRace(retryMsg)) throw retryErr;
|
|
1733
|
-
const likelyCause = /CommitmentTooNew/i.test(retryMsg) ? `the chain's block timestamps are lagging wall-clock by more than 30s across two register attempts. This is usually a transient block-production slowdown. Retry in a minute, or set DOTNS_COMMITMENT_BUFFER=60 (or higher) to absorb longer drift. Upstream fix tracked at paritytech/dotns-sdk#105.` : `the register tx reverted twice in a row. This is typically a commit-reveal timing race (block-production slowdown), but could also be a contract rejection (label already taken, PoP status mismatch). Try again in a minute; if it persists, verify the label is available. Upstream: paritytech/dotns-sdk#105.`;
|
|
1734
|
-
throw new Error(`DotNS register failed after retry: ${likelyCause} Underlying: ${retryMsg}`);
|
|
1735
|
-
}
|
|
1450
|
+
const reverse = options.reverse ?? (process.env.DOTNS_REVERSE ?? "false").toLowerCase() === "true";
|
|
1451
|
+
const [classification] = await Promise.all([
|
|
1452
|
+
this.classifyName(label),
|
|
1453
|
+
this.ensureNotRegistered(label)
|
|
1454
|
+
]);
|
|
1455
|
+
const requiredStatus = classification.requiredStatus;
|
|
1456
|
+
if (requiredStatus === ProofOfPersonhoodStatus.Reserved) {
|
|
1457
|
+
throw new Error(classification.message);
|
|
1736
1458
|
}
|
|
1459
|
+
const userStatus = await this.getUserPopStatus();
|
|
1460
|
+
if (!canRegister(requiredStatus, userStatus, trailingDigitCount)) {
|
|
1461
|
+
rejectIneligible(requiredStatus, userStatus);
|
|
1462
|
+
}
|
|
1463
|
+
const { commitment, registration } = await this.generateCommitment(label, reverse);
|
|
1464
|
+
await withSpan("deploy.dotns.submit-commitment", "2a-i. submit-commitment", {}, () => this.submitCommitment(commitment));
|
|
1465
|
+
await withSpan("deploy.dotns.wait-commitment-age", "2a-ii. wait-commitment-age", {}, () => this.waitForCommitmentAge(commitment));
|
|
1466
|
+
const pricing = await withSpan("deploy.dotns.price-validation", "2a-iii. price-validation", {}, () => this.getPriceAndValidate(label));
|
|
1467
|
+
await withSpan("deploy.dotns.finalize-registration", "2a-iv. finalize-registration", {}, () => this.finalizeRegistration(registration, pricing.priceWei));
|
|
1468
|
+
await this.verifyOwnership(label);
|
|
1737
1469
|
console.log(`
|
|
1738
|
-
Registration complete
|
|
1739
|
-
return { label, owner:
|
|
1470
|
+
Registration complete!`);
|
|
1471
|
+
return { label, owner: this.evmAddress };
|
|
1740
1472
|
});
|
|
1741
1473
|
}
|
|
1742
1474
|
disconnect() {
|
|
@@ -1746,15 +1478,12 @@ var DotNS = class {
|
|
|
1746
1478
|
this.clientWrapper = null;
|
|
1747
1479
|
this.connected = false;
|
|
1748
1480
|
}
|
|
1749
|
-
this._mnemonic = null;
|
|
1750
|
-
this._keyUri = null;
|
|
1751
1481
|
this._usesExternalSigner = false;
|
|
1752
1482
|
}
|
|
1753
1483
|
};
|
|
1754
1484
|
var dotns = new DotNS();
|
|
1755
1485
|
|
|
1756
1486
|
export {
|
|
1757
|
-
resolveDotnsCliInvocation,
|
|
1758
1487
|
fmtPas,
|
|
1759
1488
|
feeFloorFor,
|
|
1760
1489
|
RPC_ENDPOINTS,
|
|
@@ -1782,15 +1511,12 @@ export {
|
|
|
1782
1511
|
sanitizeDomainLabel,
|
|
1783
1512
|
validateDomainLabel,
|
|
1784
1513
|
isCommitmentMature,
|
|
1785
|
-
isExplicitCommitmentBuffer,
|
|
1786
|
-
isLikelyCommitmentRace,
|
|
1787
1514
|
classifyDotnsLabel,
|
|
1788
1515
|
canRegister,
|
|
1789
1516
|
simulateUserStatus,
|
|
1790
1517
|
parseDomainName,
|
|
1791
1518
|
parseProofOfPersonhoodStatus,
|
|
1792
1519
|
popStatusName,
|
|
1793
|
-
runDotnsCli,
|
|
1794
1520
|
DotNS,
|
|
1795
1521
|
dotns
|
|
1796
1522
|
};
|