bulletin-deploy 0.7.8 → 0.7.9-rc.1

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.
@@ -9,10 +9,10 @@ import {
9
9
  offerBugReport,
10
10
  scrubSecrets,
11
11
  setDeployContext
12
- } from "./chunk-BTAGLNZY.js";
13
- import "./chunk-ZTUUEMII.js";
14
- import "./chunk-R7SSZDXQ.js";
15
- import "./chunk-KRL6D3YY.js";
12
+ } from "./chunk-RUEFJ32K.js";
13
+ import "./chunk-XBONIEIK.js";
14
+ import "./chunk-ULIUVP7W.js";
15
+ import "./chunk-ODXESRRQ.js";
16
16
  import "./chunk-QGM4M3NI.js";
17
17
  export {
18
18
  buildCliFlagsSummary,
@@ -6,7 +6,7 @@ import * as path from "path";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "bulletin-deploy",
9
- version: "0.7.8",
9
+ version: "0.7.9-rc.1",
10
10
  private: false,
11
11
  repository: {
12
12
  type: "git",
@@ -2,11 +2,11 @@ import {
2
2
  classifyErrorArea,
3
3
  isInteractive,
4
4
  promptYesNo
5
- } from "./chunk-ZTUUEMII.js";
5
+ } from "./chunk-XBONIEIK.js";
6
6
  import {
7
7
  VERSION,
8
8
  getCurrentSentryTraceId
9
- } from "./chunk-R7SSZDXQ.js";
9
+ } from "./chunk-ULIUVP7W.js";
10
10
 
11
11
  // src/bug-report.ts
12
12
  import { execSync, execFileSync } from "child_process";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  setDeployContext
3
- } from "./chunk-BTAGLNZY.js";
3
+ } from "./chunk-RUEFJ32K.js";
4
4
  import {
5
5
  DotNS,
6
6
  TX_TIMEOUT_MS,
@@ -8,7 +8,7 @@ import {
8
8
  parseDomainName,
9
9
  popStatusName,
10
10
  verifyNonceAdvanced
11
- } from "./chunk-4HGXZ225.js";
11
+ } from "./chunk-YIMJSLP2.js";
12
12
  import {
13
13
  MirrorSkipped,
14
14
  mirrorToGitHubPages,
@@ -27,7 +27,7 @@ import {
27
27
  truncateAddress,
28
28
  withDeploySpan,
29
29
  withSpan
30
- } from "./chunk-R7SSZDXQ.js";
30
+ } from "./chunk-ULIUVP7W.js";
31
31
  import {
32
32
  merkleizeJS
33
33
  } from "./chunk-B7GUYYAN.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  package_default,
3
3
  writeRunState
4
- } from "./chunk-KRL6D3YY.js";
4
+ } from "./chunk-ODXESRRQ.js";
5
5
 
6
6
  // src/memory-report.ts
7
7
  import * as fs2 from "fs";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-R7SSZDXQ.js";
3
+ } from "./chunk-ULIUVP7W.js";
4
4
 
5
5
  // src/version-check.ts
6
6
  import { execSync, execFileSync } from "child_process";
@@ -2,13 +2,14 @@ import {
2
2
  captureWarning,
3
3
  setDeployAttribute,
4
4
  withSpan
5
- } from "./chunk-R7SSZDXQ.js";
5
+ } from "./chunk-ULIUVP7W.js";
6
6
  import {
7
7
  isTestnetSpecName
8
8
  } from "./chunk-RP4YJYNB.js";
9
9
 
10
10
  // src/dotns.ts
11
11
  import { spawn } from "child_process";
12
+ import crypto from "crypto";
12
13
  import { readFileSync } from "fs";
13
14
  import { dirname, join } from "path";
14
15
  import { createClient, Enum } from "polkadot-api";
@@ -22,6 +23,7 @@ import {
22
23
  decodeFunctionResult,
23
24
  keccak256,
24
25
  toBytes,
26
+ formatEther,
25
27
  isAddress,
26
28
  bytesToHex,
27
29
  isHex,
@@ -143,12 +145,36 @@ var ProofOfPersonhoodStatus = {
143
145
  ProofOfPersonhoodFull: 2,
144
146
  Reserved: 3
145
147
  };
148
+ var DOTNS_REGISTRAR_CONTROLLER_ABI = [
149
+ { inputs: [{ name: "registration", type: "tuple", components: [{ name: "label", type: "string" }, { name: "owner", type: "address" }, { name: "secret", type: "bytes32" }, { name: "reserved", type: "bool" }] }], name: "makeCommitment", outputs: [{ name: "", type: "bytes32" }], stateMutability: "view", type: "function" },
150
+ { inputs: [{ name: "commitment", type: "bytes32" }], name: "commit", outputs: [], stateMutability: "nonpayable", type: "function" },
151
+ { inputs: [], name: "minCommitmentAge", outputs: [{ name: "", type: "uint256" }], stateMutability: "view", type: "function" },
152
+ { inputs: [{ name: "commitment", type: "bytes32" }], name: "commitments", outputs: [{ name: "", type: "uint256" }], stateMutability: "view", type: "function" },
153
+ { inputs: [{ name: "registration", type: "tuple", components: [{ name: "label", type: "string" }, { name: "owner", type: "address" }, { name: "secret", type: "bytes32" }, { name: "reserved", type: "bool" }] }], name: "register", outputs: [], stateMutability: "payable", type: "function" }
154
+ ];
155
+ var DOTNS_REGISTRAR_ABI = [
156
+ { inputs: [{ name: "tokenId", type: "uint256" }], name: "ownerOf", outputs: [{ name: "", type: "address" }], stateMutability: "view", type: "function" }
157
+ ];
146
158
  var POP_RULES_ABI = [
159
+ { inputs: [{ name: "name", type: "string" }], name: "classifyName", outputs: [{ name: "requirement", type: "uint8" }, { name: "message", type: "string" }], stateMutability: "pure", type: "function" },
160
+ { inputs: [{ name: "name", type: "string" }], name: "price", outputs: [{ name: "", type: "uint256" }], stateMutability: "view", type: "function" },
161
+ { inputs: [{ name: "", type: "address" }], name: "userPopStatus", outputs: [{ name: "", type: "uint8" }], stateMutability: "view", type: "function" },
162
+ { inputs: [{ name: "status", type: "uint8" }], name: "setUserPopStatus", outputs: [], stateMutability: "nonpayable", type: "function" },
147
163
  { inputs: [{ name: "name", type: "string" }], name: "isBaseNameReserved", outputs: [{ name: "isReserved", type: "bool" }, { name: "reservationOwner", type: "address" }, { name: "expiryTimestamp", type: "uint64" }], stateMutability: "view", type: "function" }
148
164
  ];
149
165
  var DOTNS_REGISTRY_ABI = [
166
+ { 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" },
167
+ { inputs: [{ name: "node", type: "bytes32" }, { name: "newResolver", type: "address" }], name: "setResolver", outputs: [], stateMutability: "nonpayable", type: "function" },
150
168
  { inputs: [{ name: "node", type: "bytes32" }], name: "owner", outputs: [{ name: "", type: "address" }], stateMutability: "view", type: "function" }
151
169
  ];
170
+ var DOTNS_CONTENT_RESOLVER_ABI = [
171
+ { inputs: [{ name: "node", type: "bytes32" }, { name: "hash", type: "bytes" }], name: "setContenthash", outputs: [], stateMutability: "nonpayable", type: "function" },
172
+ { inputs: [{ name: "node", type: "bytes32" }], name: "contenthash", outputs: [{ name: "", type: "bytes" }], stateMutability: "view", type: "function" }
173
+ ];
174
+ var DOTNS_TEXT_RESOLVER_ABI = [
175
+ { inputs: [{ name: "node", type: "bytes32" }, { name: "key", type: "string" }, { name: "value", type: "string" }], name: "setText", outputs: [], stateMutability: "nonpayable", type: "function" },
176
+ { inputs: [{ name: "node", type: "bytes32" }, { name: "key", type: "string" }], name: "text", outputs: [{ name: "", type: "string" }], stateMutability: "view", type: "function" }
177
+ ];
152
178
  function convertToHexString(value) {
153
179
  if (!value) return "0x";
154
180
  if (typeof value?.asHex === "function") return value.asHex();
@@ -359,6 +385,11 @@ var ReviveClientWrapper = class _ReviveClientWrapper {
359
385
  const isErr = !ok || didRevert || !!err || (typeof successFlag === "boolean" ? !successFlag : false);
360
386
  return { gasConsumed, gasRequired, storageDeposit: { value: storageDepositValue }, result: { isOk, isErr, value: { data: ok ? returnData : "0x", flags: ok ? flags : 1n } } };
361
387
  }
388
+ async estimateGasForCall(originSubstrateAddress, contractAddress, value, encodedData) {
389
+ const result = await this.performDryRunCall(originSubstrateAddress, contractAddress, value, encodedData);
390
+ if (!result.result.isOk) return { success: false, gasConsumed: result.gasConsumed, storageDeposit: result.storageDeposit.value, gasRequired: result.gasRequired, revertData: result.result.value.data, revertFlags: result.result.value.flags };
391
+ return { success: true, gasConsumed: result.gasConsumed, storageDeposit: result.storageDeposit.value, gasRequired: result.gasRequired };
392
+ }
362
393
  async checkIfAccountMapped(substrateAddress) {
363
394
  try {
364
395
  const evmAddress = await this.getEvmAddress(substrateAddress);
@@ -369,6 +400,151 @@ var ReviveClientWrapper = class _ReviveClientWrapper {
369
400
  return false;
370
401
  }
371
402
  }
403
+ async ensureAccountMapped(substrateAddress, signer) {
404
+ if (isAddress(substrateAddress)) throw new Error("ensureAccountMapped requires SS58 Substrate address, not EVM H160 address");
405
+ if (this.mappedAccounts.has(substrateAddress)) return;
406
+ const isMapped = await this.checkIfAccountMapped(substrateAddress);
407
+ if (isMapped) {
408
+ this.mappedAccounts.add(substrateAddress);
409
+ return;
410
+ }
411
+ try {
412
+ await this.signAndSubmitWithRetry(() => this.client.tx.Revive.map_account(), signer, () => {
413
+ }, "Revive.map_account");
414
+ this.mappedAccounts.add(substrateAddress);
415
+ } catch (error) {
416
+ const errorMessage = error?.message || String(error);
417
+ if (errorMessage.includes("AccountAlreadyMapped")) {
418
+ this.mappedAccounts.add(substrateAddress);
419
+ return;
420
+ }
421
+ throw error;
422
+ }
423
+ }
424
+ signAndSubmitExtrinsic(extrinsic, signer, statusCallback, opts = {}) {
425
+ return new Promise((resolve, reject) => {
426
+ let settled = false;
427
+ let deadlinePoller = null;
428
+ let sub;
429
+ const finish = (fn) => (...args) => {
430
+ if (!settled) {
431
+ settled = true;
432
+ if (deadlinePoller) clearInterval(deadlinePoller);
433
+ try {
434
+ sub?.unsubscribe();
435
+ } catch {
436
+ }
437
+ fn(...args);
438
+ }
439
+ };
440
+ const startWallClockMs = Date.now();
441
+ let startChainTimeMs = null;
442
+ deadlinePoller = setInterval(async () => {
443
+ if (settled) return;
444
+ try {
445
+ if (opts.nonceFallback) {
446
+ const nonce = await verifyNonceAdvanced(opts.nonceFallback.rpcs, opts.nonceFallback.senderSS58, opts.nonceFallback.expectedNonce);
447
+ if (nonce.advanced) {
448
+ statusCallback("included");
449
+ finish(resolve)(`nonce-advanced:${nonce.witnessRpc}`);
450
+ return;
451
+ }
452
+ }
453
+ if (Date.now() - startWallClockMs > TX_WALL_CLOCK_CEILING_MS) {
454
+ statusCallback("failed");
455
+ finish(reject)(new Error(`Transaction did not settle within ${TX_WALL_CLOCK_CEILING_MS / 1e3}s wall-clock (chain may be stalled)`));
456
+ return;
457
+ }
458
+ const chainNowMs = Number(await this.client.query.Timestamp.Now.getValue());
459
+ if (startChainTimeMs === null) startChainTimeMs = chainNowMs;
460
+ const chainElapsedMs = chainNowMs - startChainTimeMs;
461
+ if (chainElapsedMs > TX_CHAIN_TIME_BUDGET_MS) {
462
+ statusCallback("failed");
463
+ finish(reject)(new Error(`Transaction not included after ${Math.floor(chainElapsedMs / 1e3)}s of chain progress (budget=${TX_CHAIN_TIME_BUDGET_MS / 1e3}s)`));
464
+ }
465
+ } catch {
466
+ }
467
+ }, 6e3);
468
+ try {
469
+ sub = extrinsic.signSubmitAndWatch(signer, { mortality: { mortal: true, period: 256 } }).subscribe({
470
+ next: (event) => {
471
+ const transactionHash = event.txHash?.toString();
472
+ switch (event.type) {
473
+ case "signed":
474
+ statusCallback("signing");
475
+ break;
476
+ case "broadcasted":
477
+ statusCallback("broadcasting");
478
+ break;
479
+ case "txBestBlocksState":
480
+ if (event.found) statusCallback("included");
481
+ break;
482
+ case "finalized":
483
+ if (event.dispatchError || event.ok === false) {
484
+ statusCallback("failed");
485
+ finish(reject)(new Error(`Transaction failed: ${event.dispatchError?.toString?.() ?? "dispatch error"}`));
486
+ return;
487
+ }
488
+ statusCallback("finalized");
489
+ finish(resolve)(transactionHash);
490
+ return;
491
+ case "invalid":
492
+ case "dropped":
493
+ statusCallback("failed");
494
+ finish(reject)(new Error(`Transaction ${event.type}`));
495
+ return;
496
+ }
497
+ },
498
+ error: (error) => {
499
+ statusCallback("failed");
500
+ finish(reject)(error);
501
+ },
502
+ complete: () => {
503
+ if (settled) return;
504
+ statusCallback("failed");
505
+ finish(reject)(new Error("transaction subscription closed before finalization"));
506
+ }
507
+ });
508
+ } catch (error) {
509
+ statusCallback("failed");
510
+ finish(reject)(error);
511
+ }
512
+ });
513
+ }
514
+ async signAndSubmitWithRetry(buildExtrinsic, signer, statusCallback, label, opts = {}) {
515
+ let lastError;
516
+ for (let attempt = 1; attempt <= DOTNS_TX_MAX_ATTEMPTS; attempt++) {
517
+ try {
518
+ return await this.signAndSubmitExtrinsic(buildExtrinsic(), signer, statusCallback, opts);
519
+ } catch (e) {
520
+ lastError = e;
521
+ const decision = classifyTxRetryDecision(e);
522
+ if (decision === "abort" || attempt === DOTNS_TX_MAX_ATTEMPTS) break;
523
+ const short = (e?.message ?? String(e)).slice(0, 80);
524
+ console.log(` ${label}: attempt ${attempt}/${DOTNS_TX_MAX_ATTEMPTS} failed (${short}), retrying...`);
525
+ }
526
+ }
527
+ throw lastError instanceof Error ? lastError : new Error(String(lastError));
528
+ }
529
+ async submitTransaction(contractAddress, value, encodedData, signerSubstrateAddress, signer, statusCallback, { rpcs, useNoncePolling }) {
530
+ await this.ensureAccountMapped(signerSubstrateAddress, signer);
531
+ const gasEstimate = await this.estimateGasForCall(signerSubstrateAddress, contractAddress, value, encodedData);
532
+ if (!gasEstimate.success) throw new Error(`Contract execution would revert: ${gasEstimate.revertData ?? "0x"}`);
533
+ const weightLimit = { proof_size: gasEstimate.gasRequired.proofSize, ref_time: gasEstimate.gasRequired.referenceTime };
534
+ const minimumStorageDeposit = 2000000000000n;
535
+ let storageDepositLimit = gasEstimate.storageDeposit === 0n ? minimumStorageDeposit : gasEstimate.storageDeposit * 120n / 100n;
536
+ if (storageDepositLimit < minimumStorageDeposit) storageDepositLimit = minimumStorageDeposit;
537
+ const buildExtrinsic = () => this.client.tx.Revive.call({ dest: Binary.fromHex(contractAddress), value, weight_limit: weightLimit, storage_deposit_limit: storageDepositLimit, data: Binary.fromHex(encodedData) });
538
+ let nonceFallback;
539
+ if (useNoncePolling) {
540
+ try {
541
+ const nonce = await fetchNonce(rpcs, signerSubstrateAddress);
542
+ nonceFallback = { rpcs, senderSS58: signerSubstrateAddress, expectedNonce: nonce };
543
+ } catch {
544
+ }
545
+ }
546
+ return await this.signAndSubmitWithRetry(buildExtrinsic, signer, statusCallback, "Revive.call", { nonceFallback });
547
+ }
372
548
  };
373
549
  async function runDotnsCli(argv, env) {
374
550
  return new Promise((resolve, reject) => {
@@ -438,6 +614,7 @@ var DotNS = class {
438
614
  // Stored credentials for CLI subprocess calls. Never logged or exposed.
439
615
  _mnemonic = null;
440
616
  _keyUri = null;
617
+ _usesExternalSigner = false;
441
618
  constructor() {
442
619
  this.client = null;
443
620
  this.clientWrapper = null;
@@ -448,27 +625,33 @@ var DotNS = class {
448
625
  this.connected = false;
449
626
  }
450
627
  async connect(options = {}) {
451
- if (options.signer || options.signerAddress) {
452
- throw new Error("External signer mode is not supported with dotns-cli subprocess \u2014 tracked as a follow-up (#158 regression notice)");
453
- }
454
628
  const rpc = options.rpc || process.env.DOTNS_RPC || RPC_ENDPOINTS[0];
455
629
  this.rpc = rpc;
456
- const mnemonicArg = options.mnemonic || process.env.DOTNS_MNEMONIC || process.env.MNEMONIC;
457
- const keyUriArg = options.keyUri || process.env.DOTNS_KEY_URI;
458
- const source = keyUriArg || mnemonicArg || DEFAULT_MNEMONIC;
459
- const isKeyUri = Boolean(keyUriArg);
460
- this._keyUri = isKeyUri ? source : null;
461
- this._mnemonic = isKeyUri ? null : source;
462
- if (options.derivationPath && !isKeyUri && this._mnemonic) {
463
- this._keyUri = `${this._mnemonic}${options.derivationPath}`;
630
+ this._usesExternalSigner = Boolean(options.signer && options.signerAddress);
631
+ let authEnv = {};
632
+ if (this._usesExternalSigner) {
633
+ this._keyUri = null;
464
634
  this._mnemonic = null;
635
+ this.signer = options.signer;
636
+ this.substrateAddress = options.signerAddress;
637
+ } else {
638
+ const mnemonicArg = options.mnemonic || process.env.DOTNS_MNEMONIC || process.env.MNEMONIC;
639
+ const keyUriArg = options.keyUri || process.env.DOTNS_KEY_URI;
640
+ const source = keyUriArg || mnemonicArg || DEFAULT_MNEMONIC;
641
+ const isKeyUri = Boolean(keyUriArg);
642
+ this._keyUri = isKeyUri ? source : null;
643
+ this._mnemonic = isKeyUri ? null : source;
644
+ if (options.derivationPath && !isKeyUri && this._mnemonic) {
645
+ this._keyUri = `${this._mnemonic}${options.derivationPath}`;
646
+ this._mnemonic = null;
647
+ }
648
+ authEnv = buildAuthEnv({ mnemonic: this._mnemonic ?? void 0, keyUri: this._keyUri ?? void 0 });
649
+ await cryptoWaitReady();
650
+ const keyring = new Keyring({ type: "sr25519" });
651
+ const account = this._keyUri ? keyring.addFromUri(this._keyUri) : keyring.addFromMnemonic(source);
652
+ this.signer = getPolkadotSigner(account.publicKey, "Sr25519", async (input) => account.sign(input));
653
+ this.substrateAddress = account.address;
465
654
  }
466
- const authEnv = buildAuthEnv({ mnemonic: this._mnemonic ?? void 0, keyUri: this._keyUri ?? void 0 });
467
- await cryptoWaitReady();
468
- const keyring = new Keyring({ type: "sr25519" });
469
- const account = this._keyUri ? keyring.addFromUri(this._keyUri) : keyring.addFromMnemonic(source);
470
- this.signer = getPolkadotSigner(account.publicKey, "Sr25519", async (input) => account.sign(input));
471
- this.substrateAddress = account.address;
472
655
  console.log(` SS58 Address: ${this.substrateAddress}`);
473
656
  try {
474
657
  this.client = createClient(getWsProvider(rpc, { heartbeatTimeout: WS_HEARTBEAT_TIMEOUT_MS }));
@@ -485,22 +668,26 @@ var DotNS = class {
485
668
  }
486
669
  if (!await this.clientWrapper.checkIfAccountMapped(this.substrateAddress)) {
487
670
  console.log(` Mapping account on Asset Hub Revive...`);
488
- try {
489
- await runDotnsCli(["account", "map", ...rpcFlag(rpc)], authEnv);
490
- } catch (e) {
491
- captureWarning("account map failed during connect (will rely on chain confirmation)", { error: e.message?.slice(0, 200) });
492
- }
493
- const mappingDeadline = Date.now() + 15e3;
494
- let mappingConfirmed = false;
495
- while (Date.now() < mappingDeadline) {
496
- if (await this.clientWrapper.checkIfAccountMapped(this.substrateAddress)) {
497
- mappingConfirmed = true;
498
- break;
671
+ if (this._usesExternalSigner) {
672
+ await this.clientWrapper.ensureAccountMapped(this.substrateAddress, this.signer);
673
+ } else {
674
+ try {
675
+ await runDotnsCli(["account", "map", ...rpcFlag(rpc)], authEnv);
676
+ } catch (e) {
677
+ captureWarning("account map failed during connect (will rely on chain confirmation)", { error: e.message?.slice(0, 200) });
678
+ }
679
+ const mappingDeadline = Date.now() + 15e3;
680
+ let mappingConfirmed = false;
681
+ while (Date.now() < mappingDeadline) {
682
+ if (await this.clientWrapper.checkIfAccountMapped(this.substrateAddress)) {
683
+ mappingConfirmed = true;
684
+ break;
685
+ }
686
+ await new Promise((r) => setTimeout(r, 1500));
687
+ }
688
+ if (!mappingConfirmed) {
689
+ 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.`);
499
690
  }
500
- await new Promise((r) => setTimeout(r, 1500));
501
- }
502
- if (!mappingConfirmed) {
503
- 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.`);
504
691
  }
505
692
  }
506
693
  console.log(` Account: mapped`);
@@ -673,9 +860,31 @@ var DotNS = class {
673
860
  }
674
861
  return decodeFunctionResult({ abi: contractAbi, functionName, data: callResult.result.value.data });
675
862
  }
863
+ async contractTransaction(contractAddress, value, contractAbi, functionName, args = [], statusCallback = () => {
864
+ }, { useNoncePolling } = {}) {
865
+ this.ensureConnected();
866
+ if (!this.clientWrapper) throw new Error("contractTransaction: polkadot-api client not available");
867
+ const encodedCallData = encodeFunctionData({ abi: contractAbi, functionName, args });
868
+ const rpcs = this.rpc ? [this.rpc, ...RPC_ENDPOINTS.filter((ep) => ep !== this.rpc)] : RPC_ENDPOINTS;
869
+ return await withTimeout(
870
+ this.clientWrapper.submitTransaction(contractAddress, value, encodedCallData, this.substrateAddress, this.signer, statusCallback, { rpcs, useNoncePolling }),
871
+ OPERATION_TIMEOUT_MS,
872
+ functionName
873
+ );
874
+ }
676
875
  async checkOwnership(label, ownerAddress = null) {
677
876
  this.ensureConnected();
678
877
  const checkAddress = (ownerAddress || this.evmAddress).toLowerCase();
878
+ if (this._usesExternalSigner) {
879
+ const tokenId = computeDomainTokenId(label);
880
+ try {
881
+ const owner = await withTimeout(this.contractCall(CONTRACTS.DOTNS_REGISTRAR, DOTNS_REGISTRAR_ABI, "ownerOf", [tokenId]), 3e4, "ownerOf");
882
+ const owned = owner.toLowerCase() === checkAddress;
883
+ return { owned, owner };
884
+ } catch {
885
+ return { owned: false, owner: null };
886
+ }
887
+ }
679
888
  try {
680
889
  const result = await runDotnsCli(
681
890
  ["lookup", "owner-of", label, "--json", ...rpcFlag(this.rpc)]
@@ -690,6 +899,11 @@ var DotNS = class {
690
899
  }
691
900
  async getUserPopStatus(ownerAddress = null) {
692
901
  this.ensureConnected();
902
+ if (this._usesExternalSigner) {
903
+ const checkAddress = ownerAddress || this.evmAddress;
904
+ const result = await withTimeout(this.contractCall(CONTRACTS.POP_RULES, POP_RULES_ABI, "userPopStatus", [checkAddress]), 3e4, "userPopStatus");
905
+ return typeof result === "bigint" ? Number(result) : result;
906
+ }
693
907
  if (ownerAddress && ownerAddress.toLowerCase() !== (this.evmAddress ?? "").toLowerCase()) {
694
908
  if (!this.clientWrapper) return 0;
695
909
  return 0;
@@ -719,6 +933,11 @@ var DotNS = class {
719
933
  return;
720
934
  }
721
935
  console.log(` Setting PoP status to ${desiredStatusName}...`);
936
+ if (this._usesExternalSigner) {
937
+ const txHash = await this.contractTransaction(CONTRACTS.POP_RULES, 0n, POP_RULES_ABI, "setUserPopStatus", [status], (s) => console.log(` ${s}`));
938
+ console.log(` Tx: ${txHash}`);
939
+ return;
940
+ }
722
941
  const statusStr = desiredStatusName.replace("ProofOfPersonhood", "").toLowerCase() || "none";
723
942
  const authEnv = buildAuthEnv({ mnemonic: this._mnemonic ?? void 0, keyUri: this._keyUri ?? void 0 });
724
943
  const result = await runDotnsCli(
@@ -745,6 +964,18 @@ var DotNS = class {
745
964
  this.ensureConnected();
746
965
  console.log(`
747
966
  Registering subdomain ${sublabel}.${parentLabel}.dot...`);
967
+ if (this._usesExternalSigner) {
968
+ const parentNode = namehash(`${parentLabel}.dot`);
969
+ const subnodeRecord = { parentNode, subLabel: sublabel, parentLabel, owner: this.evmAddress };
970
+ const txHash = await this.contractTransaction(CONTRACTS.DOTNS_REGISTRY, 0n, DOTNS_REGISTRY_ABI, "setSubnodeOwner", [subnodeRecord], (s) => console.log(` ${s}`), { useNoncePolling: true });
971
+ console.log(` Tx: ${txHash}`);
972
+ console.log(` Setting resolver...`);
973
+ const subnodeNode = namehash(`${sublabel}.${parentLabel}.dot`);
974
+ const resolverTxHash = await this.contractTransaction(CONTRACTS.DOTNS_REGISTRY, 0n, DOTNS_REGISTRY_ABI, "setResolver", [subnodeNode, CONTRACTS.DOTNS_CONTENT_RESOLVER], (s) => console.log(` ${s}`), { useNoncePolling: true });
975
+ console.log(` Tx: ${resolverTxHash}`);
976
+ console.log(` Subdomain registered!`);
977
+ return { sublabel, parentLabel, owner: this.evmAddress };
978
+ }
748
979
  const authEnv = buildAuthEnv({ mnemonic: this._mnemonic ?? void 0, keyUri: this._keyUri ?? void 0 });
749
980
  const result = await runDotnsCli(
750
981
  ["register", "subname", "-n", sublabel, "-p", parentLabel, "--json", ...rpcFlag(this.rpc)],
@@ -768,6 +999,32 @@ var DotNS = class {
768
999
  }
769
1000
  if (!ipfsCid) throw new Error(`setContenthash: cannot decode contenthash ${contenthashHex} to an IPFS CID`);
770
1001
  console.log(` Setting contenthash: ${ipfsCid}`);
1002
+ if (this._usesExternalSigner) {
1003
+ const txHash = await this.contractTransaction(CONTRACTS.DOTNS_CONTENT_RESOLVER, 0n, DOTNS_CONTENT_RESOLVER_ABI, "setContenthash", [node, contenthashHex], (s) => console.log(` ${s}`), { useNoncePolling: true });
1004
+ console.log(` Tx: ${txHash}`);
1005
+ const expected = contenthashHex.toLowerCase();
1006
+ const MAX_CHAIN_WAIT_SECONDS = 90;
1007
+ const POLL_INTERVAL_MS = 2e3;
1008
+ const startChainMs = Number(await this.clientWrapper.client.query.Timestamp.Now.getValue());
1009
+ let onChain = "0x";
1010
+ while (true) {
1011
+ onChain = (await this.getContenthash(domainName) || "0x").toLowerCase();
1012
+ if (onChain === expected) break;
1013
+ const nowChainMs = Number(await this.clientWrapper.client.query.Timestamp.Now.getValue());
1014
+ const chainElapsed = (nowChainMs - startChainMs) / 1e3;
1015
+ if (chainElapsed >= MAX_CHAIN_WAIT_SECONDS) break;
1016
+ console.log(` Awaiting finalization (chain time +${Math.floor(chainElapsed)}s / ${MAX_CHAIN_WAIT_SECONDS}s)...`);
1017
+ await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
1018
+ }
1019
+ if (onChain !== expected) {
1020
+ throw new Error(
1021
+ `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.`
1022
+ );
1023
+ }
1024
+ console.log(` Verified on-chain: ${ipfsCid}
1025
+ `);
1026
+ return { node };
1027
+ }
771
1028
  const authEnv = buildAuthEnv({ mnemonic: this._mnemonic ?? void 0, keyUri: this._keyUri ?? void 0 });
772
1029
  const setResult = await runDotnsCli(
773
1030
  ["content", "set", domainName, ipfsCid, "--json", ...rpcFlag(this.rpc)],
@@ -792,6 +1049,20 @@ var DotNS = class {
792
1049
  return withSpan("deploy.dotns.set-text", `2c. set-text ${key}`, {}, async () => {
793
1050
  this.ensureConnected();
794
1051
  console.log(` Setting text[${key}]: ${value}`);
1052
+ if (this._usesExternalSigner) {
1053
+ const node = namehash(`${domainName}.dot`);
1054
+ const txHash = await this.contractTransaction(CONTRACTS.DOTNS_RESOLVER, 0n, DOTNS_TEXT_RESOLVER_ABI, "setText", [node, key, value], (s) => console.log(` ${s}`), { useNoncePolling: true });
1055
+ console.log(` Tx: ${txHash}`);
1056
+ const onChain2 = await withTimeout(this.contractCall(CONTRACTS.DOTNS_RESOLVER, DOTNS_TEXT_RESOLVER_ABI, "text", [node, key]), 3e4, "text");
1057
+ if ((onChain2 ?? "") !== value) {
1058
+ throw new Error(
1059
+ `Post-set verification failed for text[${key}] on ${domainName}.dot: on-chain value is ${JSON.stringify(onChain2 ?? "")}, not ${JSON.stringify(value)} we just wrote. The setText tx may have silently failed, or another writer overwrote the record.`
1060
+ );
1061
+ }
1062
+ console.log(` Verified text[${key}]: ${onChain2}
1063
+ `);
1064
+ return { value, txHash };
1065
+ }
795
1066
  const authEnv = buildAuthEnv({ mnemonic: this._mnemonic ?? void 0, keyUri: this._keyUri ?? void 0 });
796
1067
  const setResult = await _cli(
797
1068
  ["text", "set", domainName, key, value, "--json", ...rpcFlag(this.rpc)],
@@ -814,11 +1085,155 @@ var DotNS = class {
814
1085
  }
815
1086
  async getContenthash(domainName) {
816
1087
  this.ensureConnected();
1088
+ if (this._usesExternalSigner) {
1089
+ const node = namehash(`${domainName}.dot`);
1090
+ const result2 = await withTimeout(
1091
+ this.contractCall(CONTRACTS.DOTNS_CONTENT_RESOLVER, DOTNS_CONTENT_RESOLVER_ABI, "contenthash", [node]),
1092
+ 3e4,
1093
+ "contenthash"
1094
+ );
1095
+ return typeof result2 === "string" ? result2 : result2?.toString?.() ?? String(result2);
1096
+ }
817
1097
  const result = await runDotnsCli(
818
1098
  ["content", "view", domainName, "--json", ...rpcFlag(this.rpc)]
819
1099
  );
820
1100
  return result.contenthash ?? "0x";
821
1101
  }
1102
+ async classifyName(label) {
1103
+ this.ensureConnected();
1104
+ if (!this._usesExternalSigner) {
1105
+ const classification = classifyDotnsLabel(label);
1106
+ return { requiredStatus: classification.status, message: classification.message };
1107
+ }
1108
+ console.log(`
1109
+ Classifying name via PopOracle...`);
1110
+ const result = await withTimeout(this.contractCall(CONTRACTS.POP_RULES, POP_RULES_ABI, "classifyName", [label]), 3e4, "classifyName");
1111
+ const requiredStatus = typeof result[0] === "bigint" ? Number(result[0]) : result[0];
1112
+ const message = result[1];
1113
+ console.log(` Required status: ${popStatusName(requiredStatus)}`);
1114
+ console.log(` Message: ${message}`);
1115
+ return { requiredStatus, message };
1116
+ }
1117
+ async ensureNotRegistered(label) {
1118
+ this.ensureConnected();
1119
+ console.log(`
1120
+ Checking availability of ${label}.dot...`);
1121
+ const tokenId = computeDomainTokenId(label);
1122
+ try {
1123
+ const owner = await withTimeout(this.contractCall(CONTRACTS.DOTNS_REGISTRAR, DOTNS_REGISTRAR_ABI, "ownerOf", [tokenId]), 3e4, "Availability check");
1124
+ if (owner !== zeroAddress) throw new Error(`Domain ${label}.dot already owned by ${owner}`);
1125
+ } catch (error) {
1126
+ const errorMessage = error instanceof Error ? error.message : String(error);
1127
+ if (errorMessage.includes("already owned")) throw error;
1128
+ }
1129
+ console.log(` ${label}.dot is available`);
1130
+ }
1131
+ async generateCommitment(label, includeReverse = false) {
1132
+ this.ensureConnected();
1133
+ console.log(`
1134
+ Generating commitment hash...`);
1135
+ label = validateDomainLabel(label);
1136
+ const secret = `0x${crypto.randomBytes(32).toString("hex")}`;
1137
+ const registration = { label, owner: this.evmAddress, secret, reserved: includeReverse };
1138
+ const commitment = await withTimeout(this.contractCall(CONTRACTS.DOTNS_REGISTRAR_CONTROLLER, DOTNS_REGISTRAR_CONTROLLER_ABI, "makeCommitment", [registration]), 3e4, "Commitment generation");
1139
+ console.log(` Commitment: ${commitment}`);
1140
+ return { commitment, registration };
1141
+ }
1142
+ async submitCommitment(commitment) {
1143
+ this.ensureConnected();
1144
+ console.log(`
1145
+ Submitting commitment...`);
1146
+ const txHash = await this.contractTransaction(CONTRACTS.DOTNS_REGISTRAR_CONTROLLER, 0n, DOTNS_REGISTRAR_CONTROLLER_ABI, "commit", [commitment], (s) => console.log(` ${s}`));
1147
+ console.log(` Tx: ${txHash}`);
1148
+ console.log(` Committed at: ${(/* @__PURE__ */ new Date()).toISOString()}`);
1149
+ }
1150
+ async waitForCommitmentAge(commitment) {
1151
+ this.ensureConnected();
1152
+ const POLL_TIMEOUT_MS = 9e4;
1153
+ const POLL_INTERVAL_MS = 3e3;
1154
+ console.log(`
1155
+ Reading minimum commitment age...`);
1156
+ const [minimumAge, initialCommitTimestamp] = await Promise.all([
1157
+ withTimeout(this.contractCall(CONTRACTS.DOTNS_REGISTRAR_CONTROLLER, DOTNS_REGISTRAR_CONTROLLER_ABI, "minCommitmentAge", []), 3e4, "minCommitmentAge"),
1158
+ withTimeout(this.contractCall(CONTRACTS.DOTNS_REGISTRAR_CONTROLLER, DOTNS_REGISTRAR_CONTROLLER_ABI, "commitments", [commitment]), 3e4, "commitments")
1159
+ ]);
1160
+ const minimumAgeSeconds = typeof minimumAge === "bigint" ? Number(minimumAge) : minimumAge;
1161
+ const commitTimestamp = typeof initialCommitTimestamp === "bigint" ? Number(initialCommitTimestamp) : initialCommitTimestamp;
1162
+ if (commitTimestamp === 0) {
1163
+ throw new Error("Commitment not found on-chain. It may not have been included in a block yet.");
1164
+ }
1165
+ console.log(` Minimum commitment age: ${minimumAgeSeconds}s`);
1166
+ console.log(` Commitment stored on-chain (timestamp: ${commitTimestamp})`);
1167
+ console.log(` Waiting for on-chain block.timestamp > ${commitTimestamp + minimumAgeSeconds}...`);
1168
+ const pollDeadline = Date.now() + POLL_TIMEOUT_MS;
1169
+ while (Date.now() < pollDeadline) {
1170
+ const nowMs = await this.clientWrapper.client.query.Timestamp.Now.getValue();
1171
+ const chainNowSeconds = Math.floor(Number(nowMs) / 1e3);
1172
+ if (isCommitmentMature(chainNowSeconds, commitTimestamp, minimumAgeSeconds)) {
1173
+ console.log(` Commitment age requirement met (chain.now=${chainNowSeconds}, target>${commitTimestamp + minimumAgeSeconds})`);
1174
+ return;
1175
+ }
1176
+ const remaining = Math.ceil((pollDeadline - Date.now()) / 1e3);
1177
+ console.log(` Chain time ${chainNowSeconds}, waiting for > ${commitTimestamp + minimumAgeSeconds} (${remaining}s left)...`);
1178
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
1179
+ }
1180
+ throw new Error(`Commitment still too new after ${POLL_TIMEOUT_MS / 1e3}s of polling chain time. The chain may be stalled.`);
1181
+ }
1182
+ async getPriceAndValidate(label) {
1183
+ this.ensureConnected();
1184
+ console.log(`
1185
+ Checking price and eligibility...`);
1186
+ label = validateDomainLabel(label);
1187
+ const baseName = stripTrailingDigits(label);
1188
+ const reservationInfo = await withTimeout(this.contractCall(CONTRACTS.POP_RULES, POP_RULES_ABI, "isBaseNameReserved", [baseName]), 3e4, "isBaseNameReserved");
1189
+ const [isReserved, reservationOwner] = reservationInfo;
1190
+ if (isReserved && reservationOwner.toLowerCase() !== this.evmAddress.toLowerCase()) throw new Error("Base name reserved for original Lite registrant");
1191
+ const classificationResult = await withTimeout(this.contractCall(CONTRACTS.POP_RULES, POP_RULES_ABI, "classifyName", [label]), 3e4, "classifyName");
1192
+ const requiredStatus = typeof classificationResult[0] === "bigint" ? Number(classificationResult[0]) : classificationResult[0];
1193
+ const message = classificationResult[1];
1194
+ const userStatus = await this.getUserPopStatus();
1195
+ if (requiredStatus === ProofOfPersonhoodStatus.Reserved) throw new Error(message);
1196
+ if (requiredStatus === ProofOfPersonhoodStatus.ProofOfPersonhoodFull) {
1197
+ if (userStatus !== ProofOfPersonhoodStatus.ProofOfPersonhoodFull) throw new Error("Requires Full Personhood verification");
1198
+ } else if (requiredStatus === ProofOfPersonhoodStatus.ProofOfPersonhoodLite) {
1199
+ if (userStatus !== ProofOfPersonhoodStatus.ProofOfPersonhoodLite && userStatus !== ProofOfPersonhoodStatus.ProofOfPersonhoodFull) throw new Error("Requires Personhood Lite verification");
1200
+ } else {
1201
+ const trailingDigitCount = countTrailingDigits(label);
1202
+ if (trailingDigitCount === 0 || userStatus === ProofOfPersonhoodStatus.ProofOfPersonhoodLite) {
1203
+ throw new Error("Personhood Lite cannot register base names \u2014 this name class requires a Full or NoStatus signer");
1204
+ }
1205
+ }
1206
+ const priceRaw = await withTimeout(this.contractCall(CONTRACTS.POP_RULES, POP_RULES_ABI, "price", [label]), 3e4, "price");
1207
+ const priceWei = typeof priceRaw === "bigint" ? priceRaw : BigInt(priceRaw);
1208
+ console.log(` Required status: ${popStatusName(requiredStatus)}`);
1209
+ console.log(` User status: ${popStatusName(userStatus)}`);
1210
+ console.log(` Price: ${formatEther(priceWei)} PAS`);
1211
+ return { priceWei, requiredStatus, userStatus, message };
1212
+ }
1213
+ async finalizeRegistration(registration, priceWei) {
1214
+ this.ensureConnected();
1215
+ console.log(`
1216
+ Finalizing registration for ${registration.label}.dot...`);
1217
+ const bufferedPaymentWei = priceWei * 110n / 100n;
1218
+ const bufferedPaymentNative = convertWeiToNative(bufferedPaymentWei);
1219
+ console.log(` Oracle price: ${formatEther(priceWei)} PAS`);
1220
+ console.log(` Paying: ${formatEther(bufferedPaymentWei)} PAS`);
1221
+ const txHash = await this.contractTransaction(CONTRACTS.DOTNS_REGISTRAR_CONTROLLER, bufferedPaymentNative, DOTNS_REGISTRAR_CONTROLLER_ABI, "register", [registration], (s) => console.log(` ${s}`));
1222
+ console.log(` Tx: ${txHash}`);
1223
+ }
1224
+ async verifyOwnership(label) {
1225
+ this.ensureConnected();
1226
+ console.log(`
1227
+ Verifying ownership...`);
1228
+ const tokenId = computeDomainTokenId(label);
1229
+ const actualOwner = await withTimeout(this.contractCall(CONTRACTS.DOTNS_REGISTRAR, DOTNS_REGISTRAR_ABI, "ownerOf", [tokenId]), 3e4, "ownerOf");
1230
+ if (actualOwner.toLowerCase() !== this.evmAddress.toLowerCase()) {
1231
+ console.log(` Expected: ${this.evmAddress}`);
1232
+ console.log(` Actual: ${actualOwner}`);
1233
+ throw new Error(`Owner mismatch for ${label}.dot`);
1234
+ }
1235
+ console.log(` Owner: ${actualOwner}`);
1236
+ }
822
1237
  // View-only readiness check. Runs every chain read needed to predict whether
823
1238
  // `register(label)` will succeed, so the caller can fail-fast BEFORE the
824
1239
  // Bulletin chunk upload. Never writes to chain. See issue #100.
@@ -1018,6 +1433,43 @@ var DotNS = class {
1018
1433
  }
1019
1434
  const explicitStatus = options.status || process.env.DOTNS_STATUS;
1020
1435
  const reverse = options.reverse ?? (process.env.DOTNS_REVERSE ?? "false").toLowerCase() === "true";
1436
+ if (this._usesExternalSigner) {
1437
+ const [classification] = await Promise.all([
1438
+ this.classifyName(label),
1439
+ this.ensureNotRegistered(label)
1440
+ ]);
1441
+ const requiredStatus = classification.requiredStatus;
1442
+ if (requiredStatus === ProofOfPersonhoodStatus.Reserved) {
1443
+ throw new Error(classification.message);
1444
+ }
1445
+ const initialUserStatus = await this.getUserPopStatus();
1446
+ const isTestnet = await this.isTestnet();
1447
+ const explicitStatusNum = explicitStatus ? parseProofOfPersonhoodStatus(explicitStatus) : void 0;
1448
+ const targetUserStatus = simulateUserStatus(initialUserStatus, requiredStatus, { explicitStatus: explicitStatusNum, isTestnet });
1449
+ if (!canRegister(requiredStatus, targetUserStatus, countTrailingDigits(label))) {
1450
+ throw new Error(
1451
+ `This label classifies as ${popStatusName(requiredStatus)}; the registrar will reject this signer (PopRules.priceWithCheck). Remediations: use a signer with Full PoP, or pick a shorter base name (6-8 chars + trailing 00) that classifies as PopLite.`
1452
+ );
1453
+ }
1454
+ if (targetUserStatus !== initialUserStatus && targetUserStatus !== ProofOfPersonhoodStatus.NoStatus) {
1455
+ await this.setUserPopStatus(targetUserStatus);
1456
+ const userStatus = await this.getUserPopStatus();
1457
+ if (userStatus !== targetUserStatus) {
1458
+ throw new Error(
1459
+ "setUserPopStatus did not land as expected (wanted " + targetUserStatus + ", got " + userStatus + "). Check RPC connectivity and POP_RULES contract."
1460
+ );
1461
+ }
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);
1469
+ console.log(`
1470
+ Registration complete!`);
1471
+ return { label, owner: this.evmAddress };
1472
+ }
1021
1473
  const statusArgs = explicitStatus ? ["-s", explicitStatus] : [];
1022
1474
  const reverseArgs = reverse ? ["-r"] : [];
1023
1475
  console.log(`
@@ -1066,6 +1518,7 @@ var DotNS = class {
1066
1518
  }
1067
1519
  this._mnemonic = null;
1068
1520
  this._keyUri = null;
1521
+ this._usesExternalSigner = false;
1069
1522
  }
1070
1523
  };
1071
1524
  var dotns = new DotNS();
package/dist/deploy.js CHANGED
@@ -26,13 +26,13 @@ import {
26
26
  storeChunkedContent,
27
27
  storeDirectory,
28
28
  storeFile
29
- } from "./chunk-RUY7MR2M.js";
30
- import "./chunk-BTAGLNZY.js";
31
- import "./chunk-ZTUUEMII.js";
32
- import "./chunk-4HGXZ225.js";
29
+ } from "./chunk-RWITW7YV.js";
30
+ import "./chunk-RUEFJ32K.js";
31
+ import "./chunk-XBONIEIK.js";
32
+ import "./chunk-YIMJSLP2.js";
33
33
  import "./chunk-HOTQDYHD.js";
34
- import "./chunk-R7SSZDXQ.js";
35
- import "./chunk-KRL6D3YY.js";
34
+ import "./chunk-ULIUVP7W.js";
35
+ import "./chunk-ODXESRRQ.js";
36
36
  import "./chunk-B7GUYYAN.js";
37
37
  import "./chunk-RP4YJYNB.js";
38
38
  import "./chunk-QGM4M3NI.js";
package/dist/dotns.d.ts CHANGED
@@ -124,7 +124,27 @@ declare class ReviveClientWrapper {
124
124
  constructor(client: any);
125
125
  getEvmAddress(substrateAddress: string): Promise<string>;
126
126
  performDryRunCall(originSubstrateAddress: string, contractAddress: string, value: bigint, encodedData: string): Promise<any>;
127
+ estimateGasForCall(originSubstrateAddress: string, contractAddress: string, value: bigint, encodedData: string): Promise<any>;
127
128
  checkIfAccountMapped(substrateAddress: string): Promise<boolean>;
129
+ ensureAccountMapped(substrateAddress: string, signer: PolkadotSigner): Promise<void>;
130
+ signAndSubmitExtrinsic(extrinsic: any, signer: PolkadotSigner, statusCallback: (status: string) => void, opts?: {
131
+ nonceFallback?: {
132
+ rpcs: string[];
133
+ senderSS58: string;
134
+ expectedNonce: number;
135
+ };
136
+ }): Promise<string>;
137
+ signAndSubmitWithRetry(buildExtrinsic: () => any, signer: PolkadotSigner, statusCallback: (status: string) => void, label: string, opts?: {
138
+ nonceFallback?: {
139
+ rpcs: string[];
140
+ senderSS58: string;
141
+ expectedNonce: number;
142
+ };
143
+ }): Promise<string>;
144
+ submitTransaction(contractAddress: string, value: bigint, encodedData: string, signerSubstrateAddress: string, signer: PolkadotSigner, statusCallback: (status: string) => void, { rpcs, useNoncePolling }: {
145
+ rpcs: string[];
146
+ useNoncePolling?: boolean;
147
+ }): Promise<string>;
128
148
  }
129
149
  declare function runDotnsCli(argv: string[], env?: Record<string, string>): Promise<unknown>;
130
150
  declare class DotNS {
@@ -137,6 +157,7 @@ declare class DotNS {
137
157
  connected: boolean;
138
158
  private _mnemonic;
139
159
  private _keyUri;
160
+ private _usesExternalSigner;
140
161
  constructor();
141
162
  connect(options?: DotNSConnectOptions): Promise<this>;
142
163
  ensureConnected(): void;
@@ -149,6 +170,9 @@ declare class DotNS {
149
170
  } | null>;
150
171
  private submitTransfer;
151
172
  contractCall(contractAddress: string, contractAbi: readonly any[], functionName: string, args?: any[]): Promise<any>;
173
+ contractTransaction(contractAddress: string, value: bigint, contractAbi: readonly any[], functionName: string, args?: any[], statusCallback?: (status: string) => void, { useNoncePolling }?: {
174
+ useNoncePolling?: boolean;
175
+ }): Promise<string>;
152
176
  checkOwnership(label: string, ownerAddress?: string | null): Promise<OwnershipResult>;
153
177
  getUserPopStatus(ownerAddress?: string | null): Promise<number>;
154
178
  setUserPopStatus(status: number): Promise<void>;
@@ -166,6 +190,20 @@ declare class DotNS {
166
190
  txHash: string;
167
191
  }>;
168
192
  getContenthash(domainName: string): Promise<string>;
193
+ classifyName(label: string): Promise<{
194
+ requiredStatus: number;
195
+ message: string;
196
+ }>;
197
+ ensureNotRegistered(label: string): Promise<void>;
198
+ generateCommitment(label: string, includeReverse?: boolean): Promise<{
199
+ commitment: any;
200
+ registration: any;
201
+ }>;
202
+ submitCommitment(commitment: any): Promise<void>;
203
+ waitForCommitmentAge(commitment: any): Promise<void>;
204
+ getPriceAndValidate(label: string): Promise<PriceValidationResult>;
205
+ finalizeRegistration(registration: any, priceWei: bigint): Promise<void>;
206
+ verifyOwnership(label: string): Promise<void>;
169
207
  preflight(label: string, explicitStatusOverride?: string): Promise<DotnsPreflightResult>;
170
208
  private gateOnFeeBalance;
171
209
  register(label: string, options?: DotNSConnectOptions & {
package/dist/dotns.js CHANGED
@@ -35,9 +35,9 @@ import {
35
35
  stripTrailingDigits,
36
36
  validateDomainLabel,
37
37
  verifyNonceAdvanced
38
- } from "./chunk-4HGXZ225.js";
39
- import "./chunk-R7SSZDXQ.js";
40
- import "./chunk-KRL6D3YY.js";
38
+ } from "./chunk-YIMJSLP2.js";
39
+ import "./chunk-ULIUVP7W.js";
40
+ import "./chunk-ODXESRRQ.js";
41
41
  import "./chunk-RP4YJYNB.js";
42
42
  import "./chunk-QGM4M3NI.js";
43
43
  export {
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  deploy
3
- } from "./chunk-RUY7MR2M.js";
4
- import "./chunk-BTAGLNZY.js";
5
- import "./chunk-ZTUUEMII.js";
3
+ } from "./chunk-RWITW7YV.js";
4
+ import "./chunk-RUEFJ32K.js";
5
+ import "./chunk-XBONIEIK.js";
6
6
  import {
7
7
  DotNS,
8
8
  parseDomainName
9
- } from "./chunk-4HGXZ225.js";
9
+ } from "./chunk-YIMJSLP2.js";
10
10
  import "./chunk-HOTQDYHD.js";
11
- import "./chunk-R7SSZDXQ.js";
11
+ import "./chunk-ULIUVP7W.js";
12
12
  import {
13
13
  VERSION,
14
14
  loadRunState,
@@ -18,7 +18,7 @@ import {
18
18
  shouldSkipStaleWarning,
19
19
  stateFilePath,
20
20
  writeRunState
21
- } from "./chunk-KRL6D3YY.js";
21
+ } from "./chunk-ODXESRRQ.js";
22
22
  import {
23
23
  merkleizeJS
24
24
  } from "./chunk-B7GUYYAN.js";
@@ -5,8 +5,8 @@ import {
5
5
  maybeWriteMemoryReport,
6
6
  safeHeap,
7
7
  sampleFromBytes
8
- } from "./chunk-R7SSZDXQ.js";
9
- import "./chunk-KRL6D3YY.js";
8
+ } from "./chunk-ULIUVP7W.js";
9
+ import "./chunk-ODXESRRQ.js";
10
10
  import "./chunk-QGM4M3NI.js";
11
11
  export {
12
12
  DEFAULT_THRESHOLD_MB,
package/dist/run-state.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  shouldSkipStaleWarning,
8
8
  stateFilePath,
9
9
  writeRunState
10
- } from "./chunk-KRL6D3YY.js";
10
+ } from "./chunk-ODXESRRQ.js";
11
11
  import "./chunk-QGM4M3NI.js";
12
12
  export {
13
13
  VERSION,
package/dist/telemetry.js CHANGED
@@ -24,8 +24,8 @@ import {
24
24
  truncateAddress,
25
25
  withDeploySpan,
26
26
  withSpan
27
- } from "./chunk-R7SSZDXQ.js";
28
- import "./chunk-KRL6D3YY.js";
27
+ } from "./chunk-ULIUVP7W.js";
28
+ import "./chunk-ODXESRRQ.js";
29
29
  import "./chunk-QGM4M3NI.js";
30
30
  export {
31
31
  VERSION,
@@ -8,9 +8,9 @@ import {
8
8
  isPreReleaseVersion,
9
9
  preReleaseWarning,
10
10
  promptYesNo
11
- } from "./chunk-ZTUUEMII.js";
12
- import "./chunk-R7SSZDXQ.js";
13
- import "./chunk-KRL6D3YY.js";
11
+ } from "./chunk-XBONIEIK.js";
12
+ import "./chunk-ULIUVP7W.js";
13
+ import "./chunk-ODXESRRQ.js";
14
14
  import "./chunk-QGM4M3NI.js";
15
15
  export {
16
16
  assessVersion,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulletin-deploy",
3
- "version": "0.7.8",
3
+ "version": "0.7.9-rc.1",
4
4
  "private": false,
5
5
  "repository": {
6
6
  "type": "git",