@parity/dotns-cli 0.5.2 → 0.5.4
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/dist/cli.js +2010 -2040
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -247567,7 +247567,7 @@ __export(exports_storeManagement, {
|
|
|
247567
247567
|
listStoreCids: () => listStoreCids,
|
|
247568
247568
|
getStoreValue: () => getStoreValue,
|
|
247569
247569
|
getStoreInfo: () => getStoreInfo,
|
|
247570
|
-
ensureStoreAuthorizations: () =>
|
|
247570
|
+
ensureStoreAuthorizations: () => ensureStoreAuthorizations,
|
|
247571
247571
|
deleteStoreValue: () => deleteStoreValue,
|
|
247572
247572
|
checkStoreAuth: () => checkStoreAuth,
|
|
247573
247573
|
cacheCidToStore: () => cacheCidToStore,
|
|
@@ -247784,7 +247784,7 @@ async function unauthorizeDotnsController(clientWrapper, substrateAddress, signe
|
|
|
247784
247784
|
console.log(source_default.gray(" tx: ") + source_default.blue(tx));
|
|
247785
247785
|
console.log(source_default.gray(" target: ") + source_default.white(targetAddress));
|
|
247786
247786
|
}
|
|
247787
|
-
async function
|
|
247787
|
+
async function ensureStoreAuthorizations(clientWrapper, substrateAddress, signer, evmAddress) {
|
|
247788
247788
|
const storeAddress = await resolveStoreAddress(clientWrapper, substrateAddress, evmAddress);
|
|
247789
247789
|
const spinner = ora("Checking Store authorizations").start();
|
|
247790
247790
|
const [controllerAuthorized, registryAuthorized] = await Promise.all([
|
|
@@ -248059,12 +248059,9 @@ function decryptKeystorePayload(ks, password) {
|
|
|
248059
248059
|
}
|
|
248060
248060
|
}
|
|
248061
248061
|
|
|
248062
|
-
// src/cli/commands/
|
|
248063
|
-
|
|
248064
|
-
|
|
248065
|
-
var MNEMONIC_PROMPT = "mnemonic";
|
|
248066
|
-
var KEY_URI_PROMPT = "key-uri";
|
|
248067
|
-
var AUTH_TYPE_UNKNOWN = "unknown";
|
|
248062
|
+
// src/cli/commands/jsonHelpers.ts
|
|
248063
|
+
init_source();
|
|
248064
|
+
init_formatting();
|
|
248068
248065
|
function getMergedOptions(command, fallback) {
|
|
248069
248066
|
const mergedOptions = { ...fallback ?? {} };
|
|
248070
248067
|
let currentCommand = command?.parent;
|
|
@@ -248072,9 +248069,8 @@ function getMergedOptions(command, fallback) {
|
|
|
248072
248069
|
if (typeof currentCommand.opts === "function") {
|
|
248073
248070
|
const parentOptions = currentCommand.opts();
|
|
248074
248071
|
for (const key in parentOptions) {
|
|
248075
|
-
|
|
248076
|
-
|
|
248077
|
-
mergedOptions[optionKey] = parentOptions[optionKey];
|
|
248072
|
+
if (!(key in mergedOptions) && parentOptions[key] !== undefined) {
|
|
248073
|
+
mergedOptions[key] = parentOptions[key];
|
|
248078
248074
|
}
|
|
248079
248075
|
}
|
|
248080
248076
|
}
|
|
@@ -248082,6 +248078,91 @@ function getMergedOptions(command, fallback) {
|
|
|
248082
248078
|
}
|
|
248083
248079
|
return mergedOptions;
|
|
248084
248080
|
}
|
|
248081
|
+
function getJsonFlag(command) {
|
|
248082
|
+
if (command && typeof command.optsWithGlobals === "function") {
|
|
248083
|
+
const options = command.optsWithGlobals();
|
|
248084
|
+
if (typeof options?.json === "boolean")
|
|
248085
|
+
return options.json;
|
|
248086
|
+
}
|
|
248087
|
+
const localOptions = command && typeof command.opts === "function" ? command.opts() : undefined;
|
|
248088
|
+
if (typeof localOptions?.json === "boolean")
|
|
248089
|
+
return localOptions.json;
|
|
248090
|
+
return false;
|
|
248091
|
+
}
|
|
248092
|
+
function emitJsonResult(jsonOutput, result) {
|
|
248093
|
+
if (jsonOutput) {
|
|
248094
|
+
console.log(JSON.stringify(result));
|
|
248095
|
+
return true;
|
|
248096
|
+
}
|
|
248097
|
+
return false;
|
|
248098
|
+
}
|
|
248099
|
+
function handleCommandError(jsonOutput, error2) {
|
|
248100
|
+
const message = formatErrorMessage(error2);
|
|
248101
|
+
if (jsonOutput) {
|
|
248102
|
+
console.error(JSON.stringify({ error: message }));
|
|
248103
|
+
} else {
|
|
248104
|
+
console.error(source_default.red(`
|
|
248105
|
+
✗ Error: ${message}
|
|
248106
|
+
`));
|
|
248107
|
+
}
|
|
248108
|
+
process.exit(1);
|
|
248109
|
+
}
|
|
248110
|
+
async function withCapturedConsole(callback) {
|
|
248111
|
+
const MAX_CAPTURED_ENTRIES = 400;
|
|
248112
|
+
const captured = [];
|
|
248113
|
+
const pushCaptured = (value) => {
|
|
248114
|
+
captured.push(value);
|
|
248115
|
+
if (captured.length > MAX_CAPTURED_ENTRIES) {
|
|
248116
|
+
captured.splice(0, captured.length - MAX_CAPTURED_ENTRIES);
|
|
248117
|
+
}
|
|
248118
|
+
};
|
|
248119
|
+
const capture = (...args) => {
|
|
248120
|
+
pushCaptured(args.map(String).join(" "));
|
|
248121
|
+
};
|
|
248122
|
+
const captureWrite = (chunk) => {
|
|
248123
|
+
pushCaptured(String(chunk));
|
|
248124
|
+
return true;
|
|
248125
|
+
};
|
|
248126
|
+
const saved = {
|
|
248127
|
+
log: console.log,
|
|
248128
|
+
error: console.error,
|
|
248129
|
+
warn: console.warn,
|
|
248130
|
+
info: console.info,
|
|
248131
|
+
stdoutWrite: process.stdout.write.bind(process.stdout),
|
|
248132
|
+
stderrWrite: process.stderr.write.bind(process.stderr)
|
|
248133
|
+
};
|
|
248134
|
+
console.log = capture;
|
|
248135
|
+
console.error = capture;
|
|
248136
|
+
console.warn = capture;
|
|
248137
|
+
console.info = capture;
|
|
248138
|
+
process.stdout.write = captureWrite;
|
|
248139
|
+
process.stderr.write = captureWrite;
|
|
248140
|
+
try {
|
|
248141
|
+
return await callback();
|
|
248142
|
+
} catch (error2) {
|
|
248143
|
+
saved.error(`[captured output before failure]
|
|
248144
|
+
` + captured.join(`
|
|
248145
|
+
`));
|
|
248146
|
+
throw error2;
|
|
248147
|
+
} finally {
|
|
248148
|
+
console.log = saved.log;
|
|
248149
|
+
console.error = saved.error;
|
|
248150
|
+
console.warn = saved.warn;
|
|
248151
|
+
console.info = saved.info;
|
|
248152
|
+
process.stdout.write = saved.stdoutWrite;
|
|
248153
|
+
process.stderr.write = saved.stderrWrite;
|
|
248154
|
+
}
|
|
248155
|
+
}
|
|
248156
|
+
function maybeQuiet(jsonOutput, callback) {
|
|
248157
|
+
return jsonOutput ? withCapturedConsole(callback) : callback();
|
|
248158
|
+
}
|
|
248159
|
+
|
|
248160
|
+
// src/cli/commands/auth.ts
|
|
248161
|
+
var DEFAULT_ACCOUNT_POINTER_FILE = ".default";
|
|
248162
|
+
var KEYSTORE_FILE_EXTENSION = ".json";
|
|
248163
|
+
var MNEMONIC_PROMPT = "mnemonic";
|
|
248164
|
+
var KEY_URI_PROMPT = "key-uri";
|
|
248165
|
+
var AUTH_TYPE_UNKNOWN = "unknown";
|
|
248085
248166
|
function resolvePasswordForCreate(options) {
|
|
248086
248167
|
const fromCli = String(options.password ?? "").trim();
|
|
248087
248168
|
if (fromCli)
|
|
@@ -252659,6 +252740,8 @@ var WAVE_TIMEOUT_MS = 60000;
|
|
|
252659
252740
|
var STORE_CALL_TIMEOUT_MS = 60000;
|
|
252660
252741
|
var FINAL_STORE_CALL_TIMEOUT_MS = 180000;
|
|
252661
252742
|
var FETCH_NONCE_TIMEOUT_MS = 15000;
|
|
252743
|
+
var WS_HEARTBEAT_TIMEOUT_MS = 300000;
|
|
252744
|
+
var WS_CONNECT_TIMEOUT_MS = 1e4;
|
|
252662
252745
|
var rxUnhandledErrorGuardInstalled = false;
|
|
252663
252746
|
function formatDispatchError(dispatchError) {
|
|
252664
252747
|
if (dispatchError.type === "Module") {
|
|
@@ -252917,7 +253000,10 @@ async function runWaveWithRetries(parameters) {
|
|
|
252917
253000
|
}
|
|
252918
253001
|
function createBulletinClient(rpc) {
|
|
252919
253002
|
installRxUnhandledErrorGuard();
|
|
252920
|
-
return createClient3(withPolkadotSdkCompat(getWsProvider(rpc
|
|
253003
|
+
return createClient3(withPolkadotSdkCompat(getWsProvider(rpc, {
|
|
253004
|
+
heartbeatTimeout: WS_HEARTBEAT_TIMEOUT_MS,
|
|
253005
|
+
timeout: WS_CONNECT_TIMEOUT_MS
|
|
253006
|
+
})));
|
|
252921
253007
|
}
|
|
252922
253008
|
async function storeContentOnBulletin(parameters) {
|
|
252923
253009
|
const {
|
|
@@ -265064,1712 +265150,1860 @@ async function prepareContext(options2) {
|
|
|
265064
265150
|
|
|
265065
265151
|
// src/cli/commands/bulletin.ts
|
|
265066
265152
|
init_constants();
|
|
265067
|
-
|
|
265068
|
-
|
|
265069
|
-
|
|
265070
|
-
|
|
265071
|
-
|
|
265072
|
-
init_dist();
|
|
265073
|
-
init_polkadotClient();
|
|
265074
|
-
|
|
265075
|
-
// src/commands/lookup.ts
|
|
265076
|
-
init_source();
|
|
265077
|
-
init_ora();
|
|
265078
|
-
init__esm();
|
|
265079
|
-
init_constants();
|
|
265080
|
-
|
|
265081
|
-
// src/utils/validation.ts
|
|
265082
|
-
init__esm();
|
|
265083
|
-
function countTrailingDigits(label) {
|
|
265084
|
-
let count2 = 0;
|
|
265085
|
-
for (let characterIndex = label.length - 1;characterIndex >= 0; characterIndex--) {
|
|
265086
|
-
const asciiCode = label.charCodeAt(characterIndex);
|
|
265087
|
-
if (asciiCode >= 48 && asciiCode <= 57) {
|
|
265088
|
-
count2++;
|
|
265089
|
-
} else {
|
|
265090
|
-
break;
|
|
265091
|
-
}
|
|
265092
|
-
}
|
|
265093
|
-
return count2;
|
|
265153
|
+
init_reporter();
|
|
265154
|
+
function cleanupHeliaAndExit(code8) {
|
|
265155
|
+
Promise.resolve().then(() => (init_heliaClient(), exports_heliaClient)).then(({ destroySharedHeliaClient: destroySharedHeliaClient2 }) => destroySharedHeliaClient2()).catch(() => {}).finally(() => process.exit(code8));
|
|
265156
|
+
setTimeout(() => process.exit(code8), 500);
|
|
265157
|
+
return;
|
|
265094
265158
|
}
|
|
265095
|
-
|
|
265096
|
-
|
|
265159
|
+
var PROFILE_SAMPLE_INTERVAL_MS = 2000;
|
|
265160
|
+
function addReporterOption(command) {
|
|
265161
|
+
return command.option("--reporter <mode>", "Progress reporter: auto, interactive, stream, or quiet", "auto");
|
|
265097
265162
|
}
|
|
265098
|
-
function
|
|
265099
|
-
|
|
265100
|
-
throw new Error("Invalid domain label: must contain only lowercase letters, digits, and hyphens, with minimum length of 3 characters");
|
|
265101
|
-
}
|
|
265102
|
-
if (label.startsWith("-") || label.endsWith("-")) {
|
|
265103
|
-
throw new Error("Invalid domain label: cannot start or end with hyphen");
|
|
265104
|
-
}
|
|
265105
|
-
const trailingDigitCount = countTrailingDigits(label);
|
|
265106
|
-
if (trailingDigitCount > 2) {
|
|
265107
|
-
throw new Error(`Invalid domain label: maximum 2 trailing digits allowed, found ${trailingDigitCount}`);
|
|
265108
|
-
}
|
|
265163
|
+
function createProfileFingerprint(input) {
|
|
265164
|
+
return createHash2("sha256").update(input).digest("hex").slice(0, 16);
|
|
265109
265165
|
}
|
|
265110
|
-
function
|
|
265111
|
-
|
|
265112
|
-
const
|
|
265113
|
-
|
|
265114
|
-
throw new Error(`Invalid governance label: base name must be 5 characters or fewer (got ${baseName.length})`);
|
|
265115
|
-
}
|
|
265166
|
+
function buildDefaultProfileOutputPath(sourcePath, fingerprint) {
|
|
265167
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
265168
|
+
const basename = path9.basename(sourcePath).replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
265169
|
+
return path9.join(os11.homedir(), ".dotns", "upload-profiles", `${timestamp}-${basename}-${fingerprint}.json`);
|
|
265116
265170
|
}
|
|
265117
|
-
|
|
265118
|
-
|
|
265119
|
-
|
|
265120
|
-
|
|
265121
|
-
|
|
265122
|
-
|
|
265123
|
-
|
|
265124
|
-
|
|
265125
|
-
|
|
265126
|
-
|
|
265127
|
-
};
|
|
265128
|
-
|
|
265129
|
-
// src/commands/lookup.ts
|
|
265130
|
-
init_contractInteractions();
|
|
265131
|
-
init_formatting();
|
|
265132
|
-
async function performDomainLookup(label, originSubstrateAddress, clientWrapper) {
|
|
265133
|
-
const fullyQualifiedDomainName = `${label}.dot`;
|
|
265134
|
-
const namehashNode = namehash(fullyQualifiedDomainName);
|
|
265135
|
-
const result = {
|
|
265136
|
-
domain: fullyQualifiedDomainName,
|
|
265137
|
-
node: namehashNode,
|
|
265138
|
-
exists: false,
|
|
265139
|
-
owner: zeroAddress,
|
|
265140
|
-
resolver: zeroAddress,
|
|
265141
|
-
store: null,
|
|
265142
|
-
resolvedAddress: null,
|
|
265143
|
-
ownerBalance: null,
|
|
265144
|
-
baseNameReservation: null
|
|
265171
|
+
function createUploadProfiler(options2) {
|
|
265172
|
+
const startedAtMs = Date.now();
|
|
265173
|
+
const startedAtIso = new Date(startedAtMs).toISOString();
|
|
265174
|
+
let latestSchedulerState = {
|
|
265175
|
+
timestampMs: startedAtMs,
|
|
265176
|
+
window: Math.max(1, options2.initialConcurrency),
|
|
265177
|
+
inFlightBytes: 0,
|
|
265178
|
+
inFlightChunks: 0,
|
|
265179
|
+
completedChunks: 0,
|
|
265180
|
+
retries: 0
|
|
265145
265181
|
};
|
|
265146
|
-
const
|
|
265147
|
-
|
|
265148
|
-
|
|
265149
|
-
|
|
265150
|
-
|
|
265151
|
-
|
|
265152
|
-
|
|
265153
|
-
|
|
265154
|
-
|
|
265155
|
-
|
|
265156
|
-
|
|
265157
|
-
|
|
265158
|
-
|
|
265159
|
-
|
|
265160
|
-
|
|
265161
|
-
|
|
265162
|
-
|
|
265163
|
-
|
|
265164
|
-
|
|
265165
|
-
|
|
265166
|
-
|
|
265167
|
-
|
|
265168
|
-
|
|
265169
|
-
|
|
265170
|
-
|
|
265171
|
-
|
|
265172
|
-
|
|
265173
|
-
|
|
265174
|
-
|
|
265175
|
-
|
|
265176
|
-
|
|
265177
|
-
|
|
265178
|
-
|
|
265179
|
-
|
|
265180
|
-
|
|
265181
|
-
|
|
265182
|
-
|
|
265183
|
-
|
|
265184
|
-
|
|
265185
|
-
|
|
265186
|
-
|
|
265187
|
-
|
|
265188
|
-
|
|
265189
|
-
|
|
265190
|
-
|
|
265191
|
-
|
|
265192
|
-
|
|
265193
|
-
|
|
265194
|
-
|
|
265195
|
-
|
|
265196
|
-
|
|
265197
|
-
|
|
265198
|
-
|
|
265199
|
-
|
|
265200
|
-
|
|
265201
|
-
|
|
265202
|
-
|
|
265203
|
-
|
|
265204
|
-
|
|
265205
|
-
} catch {
|
|
265206
|
-
console.log(source_default.gray(" balance: ") + source_default.yellow("unavailable"));
|
|
265207
|
-
}
|
|
265208
|
-
console.log();
|
|
265209
|
-
const baseName = stripTrailingDigits(label);
|
|
265210
|
-
if (baseName !== label) {
|
|
265211
|
-
result.baseNameReservation = await lookupBaseNameReservation(clientWrapper, originSubstrateAddress, baseName);
|
|
265212
|
-
displayBaseNameReservation(result.baseNameReservation);
|
|
265213
|
-
}
|
|
265214
|
-
console.log("▶ Lookup completed");
|
|
265215
|
-
return result;
|
|
265216
|
-
}
|
|
265217
|
-
async function lookupBaseNameReservation(clientWrapper, originSubstrateAddress, baseName) {
|
|
265218
|
-
try {
|
|
265219
|
-
const reservationInfo = await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_RULES, POP_RULES_ABI, "isBaseNameReserved", [baseName]);
|
|
265220
|
-
const [isReserved, reservationOwner, expirationTimestamp] = reservationInfo;
|
|
265221
|
-
return {
|
|
265222
|
-
baseName,
|
|
265223
|
-
isReserved,
|
|
265224
|
-
reservedBy: getAddress(reservationOwner),
|
|
265225
|
-
expires: expirationTimestamp > 0n ? new Date(Number(expirationTimestamp) * 1000).toISOString() : null
|
|
265226
|
-
};
|
|
265227
|
-
} catch {
|
|
265228
|
-
return {
|
|
265229
|
-
expires: null,
|
|
265230
|
-
baseName,
|
|
265231
|
-
isReserved: false,
|
|
265232
|
-
reservedBy: zeroAddress
|
|
265182
|
+
const samples = [];
|
|
265183
|
+
const waves = [];
|
|
265184
|
+
const captureSample = () => {
|
|
265185
|
+
const usage = process.memoryUsage();
|
|
265186
|
+
samples.push({
|
|
265187
|
+
timestampMs: Date.now(),
|
|
265188
|
+
heapUsed: usage.heapUsed,
|
|
265189
|
+
rss: usage.rss,
|
|
265190
|
+
arrayBuffers: usage.arrayBuffers,
|
|
265191
|
+
external: usage.external,
|
|
265192
|
+
inFlightBytes: latestSchedulerState.inFlightBytes,
|
|
265193
|
+
inFlightChunks: latestSchedulerState.inFlightChunks,
|
|
265194
|
+
window: latestSchedulerState.window,
|
|
265195
|
+
completed: latestSchedulerState.completedChunks,
|
|
265196
|
+
retries: latestSchedulerState.retries
|
|
265197
|
+
});
|
|
265198
|
+
};
|
|
265199
|
+
captureSample();
|
|
265200
|
+
const timer4 = setInterval(captureSample, PROFILE_SAMPLE_INTERVAL_MS);
|
|
265201
|
+
timer4.unref?.();
|
|
265202
|
+
const summarizeAndWrite = async (finalCid, overrideOutputPath) => {
|
|
265203
|
+
clearInterval(timer4);
|
|
265204
|
+
captureSample();
|
|
265205
|
+
const finishedAtMs = Date.now();
|
|
265206
|
+
const finishedAtIso = new Date(finishedAtMs).toISOString();
|
|
265207
|
+
const totalUploadTimeMs = Math.max(1, finishedAtMs - startedAtMs);
|
|
265208
|
+
const throughputBytesPerSecond = options2.sourceSizeBytes / totalUploadTimeMs * 1000;
|
|
265209
|
+
const peakHeapUsed = Math.max(...samples.map((sample) => sample.heapUsed));
|
|
265210
|
+
const peakRss = Math.max(...samples.map((sample) => sample.rss));
|
|
265211
|
+
const peakArrayBuffers = Math.max(...samples.map((sample) => sample.arrayBuffers));
|
|
265212
|
+
const peakExternal = Math.max(...samples.map((sample) => sample.external));
|
|
265213
|
+
const maxWindowReached = Math.max(...samples.map((sample) => sample.window));
|
|
265214
|
+
const report = {
|
|
265215
|
+
meta: {
|
|
265216
|
+
sourcePath: options2.sourcePath,
|
|
265217
|
+
sourceSizeBytes: options2.sourceSizeBytes,
|
|
265218
|
+
chunkSizeBytes: options2.chunkSizeBytes,
|
|
265219
|
+
rpc: options2.rpc,
|
|
265220
|
+
startedAtIso,
|
|
265221
|
+
finishedAtIso,
|
|
265222
|
+
heapLimitBytes: v8.getHeapStatistics().heap_size_limit,
|
|
265223
|
+
initialConcurrency: options2.initialConcurrency,
|
|
265224
|
+
maxConcurrency: options2.maxConcurrency
|
|
265225
|
+
},
|
|
265226
|
+
samples,
|
|
265227
|
+
waves,
|
|
265228
|
+
summary: {
|
|
265229
|
+
totalUploadTimeMs,
|
|
265230
|
+
totalUploadTimeSeconds: totalUploadTimeMs / 1000,
|
|
265231
|
+
elapsedMs: totalUploadTimeMs,
|
|
265232
|
+
throughputBytesPerSecond,
|
|
265233
|
+
peakHeapUsed,
|
|
265234
|
+
peakRss,
|
|
265235
|
+
peakArrayBuffers,
|
|
265236
|
+
peakExternal,
|
|
265237
|
+
retryCount: latestSchedulerState.retries,
|
|
265238
|
+
maxWindowReached,
|
|
265239
|
+
finalCid
|
|
265240
|
+
}
|
|
265233
265241
|
};
|
|
265234
|
-
|
|
265235
|
-
|
|
265236
|
-
|
|
265237
|
-
|
|
265238
|
-
|
|
265239
|
-
|
|
265240
|
-
console.log(source_default.gray(" isReserved: ") + source_default.white(String(reservation.isReserved)));
|
|
265241
|
-
console.log(source_default.gray(" owner: ") + source_default.white(reservation.reservedBy));
|
|
265242
|
-
if (reservation.expires) {
|
|
265243
|
-
console.log(source_default.gray(" expires: ") + source_default.white(reservation.expires));
|
|
265244
|
-
}
|
|
265245
|
-
console.log();
|
|
265246
|
-
}
|
|
265247
|
-
async function performOwnerOfLookup(name10, substrateAddress, clientWrapper) {
|
|
265248
|
-
if (!name10 || name10.trim().length === 0) {
|
|
265249
|
-
throw new Error("--owner-of requires a <label>");
|
|
265250
|
-
}
|
|
265251
|
-
const label = name10.trim();
|
|
265252
|
-
console.log(source_default.bold(`
|
|
265253
|
-
\uD83D\uDD0E Ownership lookup
|
|
265254
|
-
`));
|
|
265255
|
-
console.log(source_default.gray(" Label: ") + source_default.cyan(label));
|
|
265256
|
-
console.log(source_default.gray(" Domain: ") + source_default.cyan(label + ".dot"));
|
|
265257
|
-
const tokenId = computeDomainTokenId(label);
|
|
265258
|
-
let actualOwner;
|
|
265259
|
-
let isRegistered;
|
|
265260
|
-
try {
|
|
265261
|
-
actualOwner = await withTimeout(performContractCall(clientWrapper, substrateAddress, CONTRACTS.DOTNS_REGISTRAR, DOTNS_REGISTRAR_ABI, "ownerOf", [tokenId]), 30000, "ownerOf");
|
|
265262
|
-
isRegistered = actualOwner !== zeroAddress;
|
|
265263
|
-
} catch (error2) {
|
|
265264
|
-
const errorMessage = formatErrorMessage(error2);
|
|
265265
|
-
if (errorMessage.includes("Contract reverted") || errorMessage.includes("does not exist")) {
|
|
265266
|
-
actualOwner = zeroAddress;
|
|
265267
|
-
isRegistered = false;
|
|
265268
|
-
} else {
|
|
265269
|
-
throw error2;
|
|
265270
|
-
}
|
|
265271
|
-
}
|
|
265272
|
-
const ownerSubstrateAddress = isRegistered ? await clientWrapper.getSubstrateAddress(actualOwner) : "(none)";
|
|
265273
|
-
console.log(source_default.gray(`
|
|
265274
|
-
Registered: `) + source_default.white(String(isRegistered)));
|
|
265275
|
-
console.log(source_default.gray(" Owner (EVM): ") + source_default.white(isRegistered ? actualOwner : "(none)"));
|
|
265276
|
-
console.log(source_default.gray(" Owner (Substrate): ") + source_default.white(ownerSubstrateAddress));
|
|
265242
|
+
const outputPath = overrideOutputPath ?? options2.outputPath ?? buildDefaultProfileOutputPath(options2.sourcePath, createProfileFingerprint(`${options2.sourcePath}:${options2.sourceSizeBytes}:${options2.chunkSizeBytes}:${startedAtIso}`));
|
|
265243
|
+
const resolvedOutputPath = path9.resolve(outputPath);
|
|
265244
|
+
await filesystem2.mkdir(path9.dirname(resolvedOutputPath), { recursive: true });
|
|
265245
|
+
await filesystem2.writeFile(resolvedOutputPath, JSON.stringify(report, null, 2), "utf8");
|
|
265246
|
+
return { report, outputPath: resolvedOutputPath };
|
|
265247
|
+
};
|
|
265277
265248
|
return {
|
|
265278
|
-
|
|
265279
|
-
|
|
265280
|
-
|
|
265281
|
-
|
|
265282
|
-
|
|
265249
|
+
onSchedulerState: (state3) => {
|
|
265250
|
+
latestSchedulerState = state3;
|
|
265251
|
+
captureSample();
|
|
265252
|
+
},
|
|
265253
|
+
onWave: (wave) => {
|
|
265254
|
+
waves.push(wave);
|
|
265255
|
+
captureSample();
|
|
265256
|
+
},
|
|
265257
|
+
finalize: summarizeAndWrite
|
|
265283
265258
|
};
|
|
265284
265259
|
}
|
|
265285
|
-
|
|
265286
|
-
|
|
265287
|
-
|
|
265288
|
-
init_ora();
|
|
265289
|
-
init__esm();
|
|
265290
|
-
init_formatting();
|
|
265291
|
-
import crypto16 from "crypto";
|
|
265292
|
-
|
|
265293
|
-
// src/types/types.ts
|
|
265294
|
-
var ProofOfPersonhoodStatus;
|
|
265295
|
-
((ProofOfPersonhoodStatus2) => {
|
|
265296
|
-
ProofOfPersonhoodStatus2[ProofOfPersonhoodStatus2["NoStatus"] = 0] = "NoStatus";
|
|
265297
|
-
ProofOfPersonhoodStatus2[ProofOfPersonhoodStatus2["ProofOfPersonhoodLite"] = 1] = "ProofOfPersonhoodLite";
|
|
265298
|
-
ProofOfPersonhoodStatus2[ProofOfPersonhoodStatus2["ProofOfPersonhoodFull"] = 2] = "ProofOfPersonhoodFull";
|
|
265299
|
-
ProofOfPersonhoodStatus2[ProofOfPersonhoodStatus2["Reserved"] = 3] = "Reserved";
|
|
265300
|
-
})(ProofOfPersonhoodStatus ||= {});
|
|
265301
|
-
|
|
265302
|
-
// src/commands/register.ts
|
|
265303
|
-
init_constants();
|
|
265304
|
-
init_contractInteractions();
|
|
265305
|
-
init_formatting();
|
|
265306
|
-
function redactSecret(secret) {
|
|
265307
|
-
if (secret.length <= 10)
|
|
265308
|
-
return "0x" + "*".repeat(secret.length - 2);
|
|
265309
|
-
const prefix = secret.slice(0, 6);
|
|
265310
|
-
const suffix = secret.slice(-4);
|
|
265311
|
-
const redacted = "*".repeat(secret.length - 10);
|
|
265312
|
-
return `${prefix}${redacted}${suffix}`;
|
|
265313
|
-
}
|
|
265314
|
-
function convertToProofOfPersonhoodStatus(value3) {
|
|
265315
|
-
if (typeof value3 === "number")
|
|
265316
|
-
return value3;
|
|
265317
|
-
if (typeof value3 === "bigint")
|
|
265318
|
-
return Number(value3);
|
|
265319
|
-
throw new Error(`Unexpected ProofOfPersonhoodStatus type: ${typeof value3}`);
|
|
265320
|
-
}
|
|
265321
|
-
async function classifyDomainName(clientWrapper, originSubstrateAddress, label) {
|
|
265322
|
-
const spinner = ora("Classifying name via PopRules").start();
|
|
265323
|
-
try {
|
|
265324
|
-
const classificationResult = await withTimeout(performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_RULES, POP_RULES_ABI, "classifyName", [label]), 30000, "classifyName");
|
|
265325
|
-
const requiredStatus = convertToProofOfPersonhoodStatus(classificationResult[0]);
|
|
265326
|
-
const message2 = classificationResult[1];
|
|
265327
|
-
spinner.succeed("Name classification");
|
|
265328
|
-
console.log(source_default.gray(" required: ") + source_default.white(ProofOfPersonhoodStatus[requiredStatus]));
|
|
265329
|
-
console.log(source_default.gray(" message: ") + source_default.white(message2));
|
|
265330
|
-
return { requiredStatus, message: message2 };
|
|
265331
|
-
} catch (error2) {
|
|
265332
|
-
spinner.fail("Name classification failed");
|
|
265333
|
-
throw error2;
|
|
265260
|
+
async function withBulletinHumanOutput(reporterMode, callback) {
|
|
265261
|
+
if (reporterMode === "quiet") {
|
|
265262
|
+
return withCapturedConsole(callback);
|
|
265334
265263
|
}
|
|
265264
|
+
return withConsoleToStderr(callback);
|
|
265335
265265
|
}
|
|
265336
|
-
async function
|
|
265337
|
-
|
|
265338
|
-
|
|
265339
|
-
|
|
265340
|
-
|
|
265341
|
-
if (owner !== zeroAddress) {
|
|
265342
|
-
spinner.fail(`Name ${source_default.cyan(label + ".dot")} already owned by ${source_default.yellow(owner)}`);
|
|
265343
|
-
throw new Error(`Domain already owned by ${owner}`);
|
|
265344
|
-
}
|
|
265345
|
-
} catch (error2) {
|
|
265346
|
-
const errorMessage = formatErrorMessage(error2);
|
|
265347
|
-
if (errorMessage.includes("already owned"))
|
|
265348
|
-
throw error2;
|
|
265349
|
-
}
|
|
265350
|
-
spinner.succeed(`Name ${source_default.cyan(label + ".dot")} is available`);
|
|
265266
|
+
async function resolveTargetAddress(positionalAddress, mergedOptions, reporterMode) {
|
|
265267
|
+
if (positionalAddress)
|
|
265268
|
+
return positionalAddress;
|
|
265269
|
+
const context = await withBulletinHumanOutput(reporterMode, () => prepareContext({ ...mergedOptions, useBulletin: true }));
|
|
265270
|
+
return context.substrateAddress;
|
|
265351
265271
|
}
|
|
265352
|
-
|
|
265353
|
-
|
|
265354
|
-
|
|
265355
|
-
validateDomainLabel(label);
|
|
265356
|
-
const secret = `0x${crypto16.randomBytes(32).toString("hex")}`;
|
|
265357
|
-
const registration = {
|
|
265358
|
-
label,
|
|
265359
|
-
owner: ownerAddress,
|
|
265360
|
-
secret,
|
|
265361
|
-
reserved: includeReverse
|
|
265362
|
-
};
|
|
265363
|
-
const commitment = await withTimeout(performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRAR_CONTROLLER, DOTNS_REGISTRAR_CONTROLLER_ABI, "makeCommitment", [registration]), 30000, "Commitment generation");
|
|
265364
|
-
spinner.succeed("Commitment hash generated");
|
|
265365
|
-
console.log(source_default.gray(" commitment: ") + source_default.blue(commitment));
|
|
265366
|
-
console.log(source_default.gray(" hash: ") + source_default.dim("label + owner + secret + reserved"));
|
|
265367
|
-
console.log(source_default.gray(" secret: ") + source_default.yellow(redactSecret(secret)));
|
|
265368
|
-
console.log(source_default.gray(" reserved: ") + (includeReverse ? source_default.green("true") : source_default.white("false")));
|
|
265369
|
-
return { commitment, registration };
|
|
265370
|
-
} catch (error2) {
|
|
265371
|
-
spinner.fail("Failed to create commitment");
|
|
265372
|
-
throw error2;
|
|
265373
|
-
}
|
|
265272
|
+
function writeBulletinJson(payload) {
|
|
265273
|
+
process.stdout.write(`${JSON.stringify(payload)}
|
|
265274
|
+
`);
|
|
265374
265275
|
}
|
|
265375
|
-
|
|
265376
|
-
|
|
265377
|
-
|
|
265378
|
-
console.log(source_default.gray(" tx: ") + source_default.blue(transactionHash));
|
|
265379
|
-
console.log(source_default.gray(" committed: ") + source_default.white(new Date().toISOString()));
|
|
265276
|
+
function writeBulletinJsonError(error2) {
|
|
265277
|
+
writeBulletinJson({ error: formatErrorMessage(error2) });
|
|
265278
|
+
process.exit(1);
|
|
265380
265279
|
}
|
|
265381
|
-
|
|
265382
|
-
const
|
|
265383
|
-
|
|
265384
|
-
|
|
265385
|
-
|
|
265386
|
-
|
|
265387
|
-
|
|
265388
|
-
|
|
265389
|
-
const initialCommitTime = typeof initialCommitTimestamp === "bigint" ? Number(initialCommitTimestamp) : initialCommitTimestamp;
|
|
265390
|
-
if (initialCommitTime === 0) {
|
|
265391
|
-
checkSpinner.fail("Commitment not found on-chain");
|
|
265392
|
-
throw new Error("Commitment not found on-chain. It may not have been included in a block yet.");
|
|
265393
|
-
}
|
|
265394
|
-
const waitSeconds = minimumAgeSeconds + buffer2;
|
|
265395
|
-
checkSpinner.succeed(`Minimum commitment age: ${source_default.yellow(waitSeconds.toString() + "s")}`);
|
|
265396
|
-
const waitSpinner = ora(`Waiting for commitment age (${waitSeconds}s)`).start();
|
|
265397
|
-
let elapsedSeconds = 0;
|
|
265398
|
-
const intervalId = setInterval(() => {
|
|
265399
|
-
elapsedSeconds++;
|
|
265400
|
-
const remainingSeconds = waitSeconds - elapsedSeconds;
|
|
265401
|
-
waitSpinner.text = `Waiting for commitment age (${source_default.yellow(remainingSeconds + "s")} remaining)`;
|
|
265402
|
-
}, 1000);
|
|
265403
|
-
await new Promise((resolve) => setTimeout(resolve, waitSeconds * 1000));
|
|
265404
|
-
clearInterval(intervalId);
|
|
265405
|
-
waitSpinner.text = "Verifying commitment age on-chain";
|
|
265406
|
-
const pollDeadline = Date.now() + COMMITMENT_POLL_TIMEOUT_MS;
|
|
265407
|
-
while (Date.now() < pollDeadline) {
|
|
265408
|
-
const polledTimestamp = await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRAR_CONTROLLER, DOTNS_REGISTRAR_CONTROLLER_ABI, "commitments", [commitment]);
|
|
265409
|
-
const polledCommitTime = typeof polledTimestamp === "bigint" ? Number(polledTimestamp) : polledTimestamp;
|
|
265410
|
-
const nowSeconds = Math.floor(Date.now() / 1000);
|
|
265411
|
-
if (polledCommitTime > 0 && nowSeconds - polledCommitTime >= minimumAgeSeconds) {
|
|
265412
|
-
waitSpinner.succeed("Commitment age requirement met (verified on-chain)");
|
|
265280
|
+
function createPhaseHandler(reporter) {
|
|
265281
|
+
const tasks = new Map;
|
|
265282
|
+
return (event) => {
|
|
265283
|
+
const key = event.phase;
|
|
265284
|
+
const activeTask = tasks.get(key);
|
|
265285
|
+
if (event.state === "start") {
|
|
265286
|
+
activeTask?.stop();
|
|
265287
|
+
tasks.set(key, reporter.task(event.message));
|
|
265413
265288
|
return;
|
|
265414
265289
|
}
|
|
265415
|
-
|
|
265416
|
-
|
|
265417
|
-
|
|
265418
|
-
|
|
265419
|
-
|
|
265420
|
-
}
|
|
265421
|
-
async function getUserProofOfPersonhoodStatus(clientWrapper, originSubstrateAddress, ownerAddress) {
|
|
265422
|
-
const userStatusRaw = await withTimeout(performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_RULES, POP_RULES_ABI, "userPopStatus", [ownerAddress]), 30000, "userPopStatus");
|
|
265423
|
-
return convertToProofOfPersonhoodStatus(userStatusRaw);
|
|
265424
|
-
}
|
|
265425
|
-
async function getPriceAndValidateEligibility(clientWrapper, originSubstrateAddress, label, ownerAddress) {
|
|
265426
|
-
const spinner = ora("Pricing via PopRules.price").start();
|
|
265427
|
-
try {
|
|
265428
|
-
validateDomainLabel(label);
|
|
265429
|
-
const baseName = stripTrailingDigits(label);
|
|
265430
|
-
const reservationInfo = await withTimeout(performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_RULES, POP_RULES_ABI, "isBaseNameReserved", [baseName]), 30000, "isBaseNameReserved");
|
|
265431
|
-
const [isReserved, reservationOwner] = reservationInfo;
|
|
265432
|
-
if (isReserved && checksumAddress(reservationOwner) !== checksumAddress(ownerAddress)) {
|
|
265433
|
-
spinner.fail("Eligibility failed");
|
|
265434
|
-
throw new Error("Base name reserved for original Lite registrant");
|
|
265435
|
-
}
|
|
265436
|
-
const classificationResult = await withTimeout(performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_RULES, POP_RULES_ABI, "priceWithoutCheck", [label, ownerAddress]), 30000, "priceWithoutCheck");
|
|
265437
|
-
const requiredStatus = convertToProofOfPersonhoodStatus(classificationResult.status);
|
|
265438
|
-
const message2 = classificationResult.message;
|
|
265439
|
-
const userStatus = await getUserProofOfPersonhoodStatus(clientWrapper, originSubstrateAddress, ownerAddress);
|
|
265440
|
-
if (requiredStatus === 3 /* Reserved */) {
|
|
265441
|
-
spinner.fail("Eligibility failed");
|
|
265442
|
-
throw new Error(message2);
|
|
265443
|
-
}
|
|
265444
|
-
if (requiredStatus === 2 /* ProofOfPersonhoodFull */) {
|
|
265445
|
-
if (userStatus !== 2 /* ProofOfPersonhoodFull */) {
|
|
265446
|
-
spinner.fail("Eligibility failed");
|
|
265447
|
-
throw new Error("Requires Full Personhood verification");
|
|
265290
|
+
if (event.state === "update") {
|
|
265291
|
+
if (activeTask) {
|
|
265292
|
+
activeTask.update(event.message);
|
|
265293
|
+
} else {
|
|
265294
|
+
tasks.set(key, reporter.task(event.message));
|
|
265448
265295
|
}
|
|
265449
|
-
|
|
265450
|
-
|
|
265451
|
-
|
|
265452
|
-
|
|
265296
|
+
return;
|
|
265297
|
+
}
|
|
265298
|
+
if (event.state === "success") {
|
|
265299
|
+
if (activeTask) {
|
|
265300
|
+
activeTask.succeed(event.message);
|
|
265301
|
+
tasks.delete(key);
|
|
265302
|
+
} else {
|
|
265303
|
+
reporter.success(event.message);
|
|
265453
265304
|
}
|
|
265454
|
-
|
|
265455
|
-
|
|
265456
|
-
|
|
265457
|
-
|
|
265458
|
-
|
|
265459
|
-
|
|
265305
|
+
return;
|
|
265306
|
+
}
|
|
265307
|
+
if (event.state === "warning") {
|
|
265308
|
+
if (activeTask) {
|
|
265309
|
+
activeTask.warn(event.message);
|
|
265310
|
+
tasks.delete(key);
|
|
265311
|
+
} else {
|
|
265312
|
+
reporter.warn(event.message);
|
|
265460
265313
|
}
|
|
265314
|
+
return;
|
|
265461
265315
|
}
|
|
265462
|
-
|
|
265463
|
-
|
|
265464
|
-
|
|
265465
|
-
|
|
265466
|
-
console.log(source_default.gray(" price: ") + source_default.green(`${classificationResult.priceWei > 0n ? formatWeiAsEther(classificationResult.priceWei) : 0n} PAS`));
|
|
265467
|
-
return {
|
|
265468
|
-
priceWei: classificationResult.price ?? classificationResult.priceWei,
|
|
265469
|
-
requiredStatus,
|
|
265470
|
-
userStatus,
|
|
265471
|
-
message: message2,
|
|
265472
|
-
status: requiredStatus,
|
|
265473
|
-
price: classificationResult.price ?? classificationResult.priceWei
|
|
265474
|
-
};
|
|
265475
|
-
} catch (error2) {
|
|
265476
|
-
if (!spinner.isSpinning)
|
|
265477
|
-
throw error2;
|
|
265478
|
-
spinner.fail("Pricing failed");
|
|
265479
|
-
throw error2;
|
|
265480
|
-
}
|
|
265481
|
-
}
|
|
265482
|
-
async function finalizeRegularRegistration(clientWrapper, substrateAddress, signer, registration, priceWei) {
|
|
265483
|
-
const spinner = ora(`Registering ${source_default.cyan(registration.label + ".dot")}`).start();
|
|
265484
|
-
try {
|
|
265485
|
-
const bufferedPaymentWei = priceWei * 110n / 100n;
|
|
265486
|
-
const bufferedPaymentNative = convertWeiToNative(bufferedPaymentWei);
|
|
265487
|
-
console.log(source_default.gray(" oracle: ") + source_default.green(formatWeiAsEther(priceWei) + " PAS"));
|
|
265488
|
-
console.log(source_default.gray(" paying: ") + source_default.green(formatWeiAsEther(bufferedPaymentWei) + " PAS"));
|
|
265489
|
-
const transactionHash = await submitContractTransaction(clientWrapper, CONTRACTS.DOTNS_REGISTRAR_CONTROLLER, bufferedPaymentNative, DOTNS_REGISTRAR_CONTROLLER_ABI, "register", [registration], substrateAddress, signer, spinner, "Registration");
|
|
265490
|
-
console.log(source_default.gray(" tx: ") + source_default.blue(transactionHash));
|
|
265491
|
-
console.log(source_default.gray(" paid: ") + source_default.green(formatWeiAsEther(bufferedPaymentWei) + " PAS"));
|
|
265492
|
-
} catch (error2) {
|
|
265493
|
-
spinner.fail("Registration failed");
|
|
265494
|
-
throw error2;
|
|
265495
|
-
}
|
|
265496
|
-
}
|
|
265497
|
-
async function finalizeGovernanceRegistration(clientWrapper, substrateAddress, signer, registration) {
|
|
265498
|
-
const spinner = ora(`Registering governance name ${source_default.cyan(registration.label + ".dot")}`).start();
|
|
265499
|
-
try {
|
|
265500
|
-
const transactionHash = await submitContractTransaction(clientWrapper, CONTRACTS.DOTNS_REGISTRAR_CONTROLLER, 0n, DOTNS_REGISTRAR_CONTROLLER_ABI, "registerReserved", [registration], substrateAddress, signer, spinner, "Governance Registration");
|
|
265501
|
-
console.log(source_default.gray(" tx: ") + source_default.blue(transactionHash));
|
|
265502
|
-
} catch (error2) {
|
|
265503
|
-
spinner.fail("Governance registration failed");
|
|
265504
|
-
throw error2;
|
|
265505
|
-
}
|
|
265506
|
-
}
|
|
265507
|
-
async function registerSubnode(clientWrapper, substrateAddress, signer, sublabel, parentLabel, ownerAddress) {
|
|
265508
|
-
const fullName = `${sublabel}.${parentLabel}.dot`;
|
|
265509
|
-
const spinner = ora(`Registering subname ${source_default.cyan(fullName)}`).start();
|
|
265510
|
-
try {
|
|
265511
|
-
const parentNode = namehash(`${parentLabel}.dot`);
|
|
265512
|
-
const subnodeRecord = {
|
|
265513
|
-
parentNode,
|
|
265514
|
-
subLabel: sublabel,
|
|
265515
|
-
parentLabel,
|
|
265516
|
-
owner: ownerAddress
|
|
265517
|
-
};
|
|
265518
|
-
const transactionHash = await submitContractTransaction(clientWrapper, CONTRACTS.DOTNS_REGISTRY, 0n, DOTNS_REGISTRY_ABI, "setSubnodeOwner", [subnodeRecord], substrateAddress, signer, spinner, "Subname registration");
|
|
265519
|
-
console.log(source_default.gray(" tx: ") + source_default.blue(transactionHash));
|
|
265520
|
-
return transactionHash;
|
|
265521
|
-
} catch (error2) {
|
|
265522
|
-
spinner.fail("Subname registration failed");
|
|
265523
|
-
throw error2;
|
|
265524
|
-
}
|
|
265525
|
-
}
|
|
265526
|
-
async function verifyDomainOwnership(clientWrapper, originSubstrateAddress, label, expectedOwner) {
|
|
265527
|
-
const spinner = ora("Verifying minted ownership").start();
|
|
265528
|
-
try {
|
|
265529
|
-
const tokenId = computeDomainTokenId(label);
|
|
265530
|
-
const actualOwner = await withTimeout(performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRAR, DOTNS_REGISTRAR_ABI, "ownerOf", [tokenId]), 30000, "ownerOf");
|
|
265531
|
-
if (checksumAddress(actualOwner) !== checksumAddress(expectedOwner)) {
|
|
265532
|
-
spinner.fail("Ownership verification failed");
|
|
265533
|
-
console.log(source_default.gray(" expected: ") + source_default.white(expectedOwner));
|
|
265534
|
-
console.log(source_default.gray(" actual: ") + source_default.white(actualOwner));
|
|
265535
|
-
throw new Error(`Owner mismatch for ${label}.dot`);
|
|
265316
|
+
if (activeTask) {
|
|
265317
|
+
activeTask.fail(event.message);
|
|
265318
|
+
tasks.delete(key);
|
|
265319
|
+
return;
|
|
265536
265320
|
}
|
|
265537
|
-
|
|
265538
|
-
|
|
265539
|
-
return actualOwner;
|
|
265540
|
-
} catch (error2) {
|
|
265541
|
-
spinner.fail("Ownership verification failed");
|
|
265542
|
-
throw error2;
|
|
265543
|
-
}
|
|
265544
|
-
}
|
|
265545
|
-
async function displayDeployedStore(clientWrapper, originSubstrateAddress, ownerAddress) {
|
|
265546
|
-
const spinner = ora("Reading deployed Store address").start();
|
|
265547
|
-
try {
|
|
265548
|
-
const storeAddress = await withTimeout(performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.STORE_FACTORY, STORE_FACTORY_ABI, "getDeployedStore", [ownerAddress]), 30000, "getDeployedStore");
|
|
265549
|
-
spinner.succeed("Store");
|
|
265550
|
-
console.log(source_default.gray(" store: ") + (storeAddress === zeroAddress ? source_default.yellow("not deployed") : source_default.cyan(storeAddress)));
|
|
265551
|
-
} catch (error2) {
|
|
265552
|
-
spinner.fail("Failed to read Store address");
|
|
265553
|
-
throw error2;
|
|
265554
|
-
}
|
|
265321
|
+
reporter.fail(event.message);
|
|
265322
|
+
};
|
|
265555
265323
|
}
|
|
265556
|
-
|
|
265557
|
-
|
|
265558
|
-
|
|
265559
|
-
|
|
265560
|
-
|
|
265561
|
-
const [controllerAuthorized, registryAuthorized] = await Promise.all([
|
|
265562
|
-
Boolean(await performContractCall(clientWrapper, substrateAddress, storeAddress, STORE_ABI, "isAuthorized", [CONTRACTS.DOTNS_REGISTRAR_CONTROLLER])),
|
|
265563
|
-
Boolean(await performContractCall(clientWrapper, substrateAddress, storeAddress, STORE_ABI, "isAuthorized", [CONTRACTS.DOTNS_REGISTRY]))
|
|
265564
|
-
]);
|
|
265565
|
-
if (controllerAuthorized && registryAuthorized) {
|
|
265566
|
-
spinner.succeed("Store authorizations verified");
|
|
265567
|
-
console.log(source_default.gray(" controller: ") + source_default.white(CONTRACTS.DOTNS_REGISTRAR_CONTROLLER));
|
|
265568
|
-
console.log(source_default.gray(" registry: ") + source_default.white(CONTRACTS.DOTNS_REGISTRY));
|
|
265569
|
-
return;
|
|
265570
|
-
}
|
|
265571
|
-
spinner.warn("Store authorizations need update");
|
|
265572
|
-
if (!controllerAuthorized) {
|
|
265573
|
-
const controllerSpinner = ora("Authorizing registrar controller as Store writer").start();
|
|
265574
|
-
const tx = await submitContractTransaction(clientWrapper, storeAddress, 0n, STORE_ABI, "authorizeStore", [CONTRACTS.DOTNS_REGISTRAR_CONTROLLER], substrateAddress, signer, controllerSpinner, "Authorize controller");
|
|
265575
|
-
console.log(source_default.gray(" tx: ") + source_default.blue(tx));
|
|
265576
|
-
console.log(source_default.gray(" controller: ") + source_default.white(CONTRACTS.DOTNS_REGISTRAR_CONTROLLER));
|
|
265577
|
-
}
|
|
265578
|
-
if (!registryAuthorized) {
|
|
265579
|
-
const registrySpinner = ora("Authorizing registry as Store writer").start();
|
|
265580
|
-
const tx = await submitContractTransaction(clientWrapper, storeAddress, 0n, STORE_ABI, "authorizeStore", [CONTRACTS.DOTNS_REGISTRY], substrateAddress, signer, registrySpinner, "Authorize registry");
|
|
265581
|
-
console.log(source_default.gray(" tx: ") + source_default.blue(tx));
|
|
265582
|
-
console.log(source_default.gray(" registry: ") + source_default.white(CONTRACTS.DOTNS_REGISTRY));
|
|
265583
|
-
}
|
|
265324
|
+
function createRetryHandler(reporter) {
|
|
265325
|
+
return ({ label, retry, totalAttempts, delayMs, errorMessage }) => {
|
|
265326
|
+
reporter.warn(`${label} attempt ${retry + 1}/${totalAttempts} failed: ${errorMessage}`);
|
|
265327
|
+
reporter.detail(`retrying in ${(delayMs / 1000).toFixed(delayMs >= 1000 ? 1 : 0)}s`);
|
|
265328
|
+
};
|
|
265584
265329
|
}
|
|
265585
|
-
|
|
265586
|
-
const
|
|
265587
|
-
|
|
265588
|
-
|
|
265589
|
-
|
|
265590
|
-
|
|
265591
|
-
|
|
265592
|
-
|
|
265593
|
-
|
|
265594
|
-
|
|
265330
|
+
function createChunkedUploadMonitor(reporter, phaseHandler, fileSize, chunkSizeBytes, totalChunks) {
|
|
265331
|
+
const heartbeatIntervalMs = 15000;
|
|
265332
|
+
let latestState = null;
|
|
265333
|
+
let heartbeatTimer;
|
|
265334
|
+
const startedAtMs = Date.now();
|
|
265335
|
+
const stopHeartbeat = () => {
|
|
265336
|
+
if (heartbeatTimer) {
|
|
265337
|
+
clearInterval(heartbeatTimer);
|
|
265338
|
+
heartbeatTimer = undefined;
|
|
265339
|
+
}
|
|
265340
|
+
};
|
|
265341
|
+
const emitHeartbeat = () => {
|
|
265342
|
+
if (!latestState || latestState.inFlightChunks === 0) {
|
|
265343
|
+
stopHeartbeat();
|
|
265595
265344
|
return;
|
|
265596
265345
|
}
|
|
265597
|
-
|
|
265598
|
-
const transactionHash = await submitContractTransaction(clientWrapper, CONTRACTS.DOTNS_RULES, 0n, POP_RULES_ABI, "setUserPopStatus", [status], substrateAddress, signer, updateSpinner, "PoP status update");
|
|
265599
|
-
console.log(source_default.gray(" tx: ") + source_default.blue(transactionHash));
|
|
265600
|
-
} catch (error2) {
|
|
265601
|
-
if (checkSpinner.isSpinning)
|
|
265602
|
-
checkSpinner.fail("Failed to check PoP status");
|
|
265603
|
-
throw error2;
|
|
265604
|
-
}
|
|
265605
|
-
}
|
|
265606
|
-
|
|
265607
|
-
// src/cli/commands/lookup.ts
|
|
265608
|
-
init_env();
|
|
265609
|
-
init_formatting();
|
|
265610
|
-
|
|
265611
|
-
// src/cli/transfer.ts
|
|
265612
|
-
init_source();
|
|
265613
|
-
init_ora();
|
|
265614
|
-
init__esm();
|
|
265615
|
-
init_constants();
|
|
265616
|
-
init_formatting();
|
|
265617
|
-
init_contractInteractions();
|
|
265618
|
-
function toChecksummed(a2) {
|
|
265619
|
-
return checksumAddress(a2);
|
|
265620
|
-
}
|
|
265621
|
-
function isLabelLike(input) {
|
|
265622
|
-
return /^[a-z0-9-]{3,}$/.test(input);
|
|
265623
|
-
}
|
|
265624
|
-
function asDotLabel(input) {
|
|
265625
|
-
const raw = input.trim().toLowerCase();
|
|
265626
|
-
if (raw.endsWith(".dot"))
|
|
265627
|
-
return raw.slice(0, -4);
|
|
265628
|
-
return raw;
|
|
265629
|
-
}
|
|
265630
|
-
async function ownerOfLabel(clientWrapper, originSubstrateAddress, label) {
|
|
265631
|
-
const tokenId = computeDomainTokenId(label);
|
|
265632
|
-
return await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRAR, DOTNS_REGISTRAR_ABI, "ownerOf", [tokenId]);
|
|
265633
|
-
}
|
|
265634
|
-
async function resolveTransferRecipient(clientWrapper, originSubstrateAddress, recipientIdentifier) {
|
|
265635
|
-
const input = recipientIdentifier.trim();
|
|
265636
|
-
if (isAddress(input))
|
|
265637
|
-
return toChecksummed(input);
|
|
265638
|
-
const label = asDotLabel(input);
|
|
265639
|
-
if (isLabelLike(label)) {
|
|
265640
|
-
const spinner2 = ora(`Resolving ${source_default.cyan(label + ".dot")} to owner address`).start();
|
|
265641
|
-
const ownerAddress = await ownerOfLabel(clientWrapper, originSubstrateAddress, label);
|
|
265642
|
-
if (ownerAddress === zeroAddress) {
|
|
265643
|
-
spinner2.fail(`No owner found for ${source_default.cyan(label + ".dot")} (unregistered)`);
|
|
265644
|
-
throw new Error(`Domain ${label}.dot has no owner`);
|
|
265645
|
-
}
|
|
265646
|
-
spinner2.succeed(`${source_default.cyan(label + ".dot")} → ${source_default.white(toChecksummed(ownerAddress))}`);
|
|
265647
|
-
return toChecksummed(ownerAddress);
|
|
265648
|
-
}
|
|
265649
|
-
const spinner = ora(`Resolving recipient address`).start();
|
|
265650
|
-
const evmAddress = await clientWrapper.getEvmAddress(input);
|
|
265651
|
-
spinner.succeed(`${source_default.white(input)} → ${source_default.white(toChecksummed(evmAddress))}`);
|
|
265652
|
-
return toChecksummed(evmAddress);
|
|
265653
|
-
}
|
|
265654
|
-
async function transferDomain(clientWrapper, originSubstrateAddress, signer, fromAddress, toAddress, label) {
|
|
265655
|
-
const spinner = ora().start();
|
|
265656
|
-
const normLabel = asDotLabel(label);
|
|
265657
|
-
spinner.text = `Validating ${source_default.cyan(normLabel + ".dot")}`;
|
|
265658
|
-
validateDomainLabel(normLabel);
|
|
265659
|
-
spinner.succeed(`Valid: ${source_default.cyan(normLabel + ".dot")}`);
|
|
265660
|
-
spinner.start(`Checking owner of ${source_default.cyan(normLabel + ".dot")}`);
|
|
265661
|
-
const tokenId = computeDomainTokenId(normLabel);
|
|
265662
|
-
const currentOwner = await ownerOfLabel(clientWrapper, originSubstrateAddress, normLabel);
|
|
265663
|
-
const currentOwnerC = toChecksummed(currentOwner);
|
|
265664
|
-
spinner.succeed(`Owner: ${source_default.cyan(normLabel + ".dot")} → ${source_default.white(currentOwnerC)}`);
|
|
265665
|
-
const fromC = toChecksummed(fromAddress);
|
|
265666
|
-
const toC = toChecksummed(toAddress);
|
|
265667
|
-
if (currentOwner === zeroAddress) {
|
|
265668
|
-
spinner.fail(`${source_default.cyan(normLabel + ".dot")} is not registered`);
|
|
265669
|
-
throw new Error(`Cannot transfer: ${normLabel}.dot is not registered`);
|
|
265670
|
-
}
|
|
265671
|
-
if (currentOwnerC !== fromC) {
|
|
265672
|
-
spinner.fail(`Not authorized to transfer ${source_default.cyan(normLabel + ".dot")}`);
|
|
265673
|
-
console.log(source_default.gray(" expected owner: ") + source_default.white(fromC));
|
|
265674
|
-
console.log(source_default.gray(" on-chain owner: ") + source_default.white(currentOwnerC));
|
|
265675
|
-
throw new Error(`Cannot transfer: ${normLabel}.dot owned by ${currentOwnerC}`);
|
|
265676
|
-
}
|
|
265677
|
-
try {
|
|
265678
|
-
const syncSpinner = ora(`Syncing label ${source_default.cyan(normLabel)} with registrar`).start();
|
|
265679
|
-
await submitContractTransaction(clientWrapper, CONTRACTS.DOTNS_REGISTRAR, 0n, DOTNS_REGISTRAR_ABI, "syncLabel", [tokenId, normLabel], originSubstrateAddress, signer, syncSpinner, "Label sync");
|
|
265680
|
-
syncSpinner.succeed("Label synced");
|
|
265681
|
-
} catch (error2) {
|
|
265682
|
-
const errorMessage = formatErrorMessage(error2);
|
|
265683
|
-
if (!errorMessage.includes("LabelAlreadySet")) {
|
|
265684
|
-
console.log(source_default.yellow(" Label sync skipped: " + errorMessage.split(`
|
|
265685
|
-
`)[0]));
|
|
265686
|
-
}
|
|
265687
|
-
}
|
|
265688
|
-
spinner.start(`Submitting transfer ${source_default.cyan(normLabel + ".dot")} → ${source_default.green(toC)}`);
|
|
265689
|
-
const transactionHash = await submitContractTransaction(clientWrapper, CONTRACTS.DOTNS_REGISTRAR, 0n, DOTNS_REGISTRAR_ABI, "transferFrom", [fromC, toC, tokenId], originSubstrateAddress, signer, spinner, "Transfer");
|
|
265690
|
-
spinner.succeed(`Transfer finalized`);
|
|
265691
|
-
console.log(source_default.gray(" tx: ") + source_default.blue(transactionHash));
|
|
265692
|
-
console.log(source_default.gray(" from: ") + source_default.yellow(fromC));
|
|
265693
|
-
console.log(source_default.gray(" to: ") + source_default.green(toC));
|
|
265694
|
-
console.log(source_default.gray(" name: ") + source_default.cyan(normLabel + ".dot"));
|
|
265695
|
-
}
|
|
265696
|
-
|
|
265697
|
-
// src/cli/commands/register.ts
|
|
265698
|
-
init_source();
|
|
265699
|
-
init__esm();
|
|
265700
|
-
|
|
265701
|
-
// src/cli/labels.ts
|
|
265702
|
-
function generateRandomLabel(status) {
|
|
265703
|
-
const alphabet4 = "abcdefghijklmnopqrstuvwxyz";
|
|
265704
|
-
const alphanumeric = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
265705
|
-
const randomInteger = (maxExclusive) => Math.floor(Math.random() * maxExclusive);
|
|
265706
|
-
const randomCharacters = (characterSet, count2) => {
|
|
265707
|
-
let result = "";
|
|
265708
|
-
for (let i2 = 0;i2 < count2; i2++)
|
|
265709
|
-
result += characterSet[randomInteger(characterSet.length)];
|
|
265710
|
-
return result;
|
|
265346
|
+
reporter.detail(`heartbeat | ${latestState.completedChunks}/${totalChunks} chunks | window=${latestState.window} | in-flight=${latestState.inFlightChunks} | bytes=${formatBytes(latestState.inFlightBytes)} | retries=${latestState.retries} | elapsed=${formatDuration((Date.now() - startedAtMs) / 1000)}`);
|
|
265711
265347
|
};
|
|
265712
|
-
|
|
265713
|
-
|
|
265714
|
-
|
|
265715
|
-
|
|
265716
|
-
|
|
265717
|
-
|
|
265718
|
-
|
|
265348
|
+
return {
|
|
265349
|
+
onSchedulerState(state3) {
|
|
265350
|
+
latestState = state3;
|
|
265351
|
+
if (reporter.mode !== "stream") {
|
|
265352
|
+
return;
|
|
265353
|
+
}
|
|
265354
|
+
if (state3.inFlightChunks > 0 && !heartbeatTimer) {
|
|
265355
|
+
heartbeatTimer = setInterval(emitHeartbeat, heartbeatIntervalMs);
|
|
265356
|
+
heartbeatTimer.unref?.();
|
|
265357
|
+
} else if (state3.inFlightChunks === 0) {
|
|
265358
|
+
stopHeartbeat();
|
|
265359
|
+
}
|
|
265360
|
+
},
|
|
265361
|
+
onWave(wave) {
|
|
265362
|
+
const completedChunks = latestState?.completedChunks ?? 0;
|
|
265363
|
+
const bytesUploaded = Math.min(fileSize, completedChunks * chunkSizeBytes);
|
|
265364
|
+
const throughputBytesPerSecond = wave.durationMs > 0 ? wave.succeeded * chunkSizeBytes * 1000 / wave.durationMs : 0;
|
|
265365
|
+
const message2 = `wave #${wave.wave} complete | ${completedChunks}/${totalChunks} chunks | ${formatBytes(bytesUploaded)}/${formatBytes(fileSize)} | ${(wave.durationMs / 1000).toFixed(1)}s | window=${wave.window} | retries=${wave.retries} | ${formatBytes(throughputBytesPerSecond)}/s`;
|
|
265366
|
+
if (reporter.mode === "interactive") {
|
|
265367
|
+
phaseHandler({ phase: "upload", state: "update", message: message2 });
|
|
265368
|
+
} else {
|
|
265369
|
+
reporter.line(message2);
|
|
265370
|
+
}
|
|
265371
|
+
},
|
|
265372
|
+
stop() {
|
|
265373
|
+
stopHeartbeat();
|
|
265374
|
+
}
|
|
265719
265375
|
};
|
|
265720
|
-
if (status === 1 /* ProofOfPersonhoodLite */) {
|
|
265721
|
-
const baseLength = 6 + randomInteger(3);
|
|
265722
|
-
return baseEndingWithLetter(baseLength) + twoDigits();
|
|
265723
|
-
}
|
|
265724
|
-
if (status === 0 /* NoStatus */) {
|
|
265725
|
-
const baseLength = 9 + randomInteger(6);
|
|
265726
|
-
return baseEndingWithLetter(baseLength) + twoDigits();
|
|
265727
|
-
}
|
|
265728
|
-
if (status === 2 /* ProofOfPersonhoodFull */) {
|
|
265729
|
-
const baseLength = randomInteger(2) === 0 ? 6 + randomInteger(3) : 9 + randomInteger(6);
|
|
265730
|
-
return baseEndingWithLetter(baseLength);
|
|
265731
|
-
}
|
|
265732
|
-
throw new Error("Cannot auto-generate Reserved names");
|
|
265733
|
-
}
|
|
265734
|
-
function parseProofOfPersonhoodStatus(statusString) {
|
|
265735
|
-
const normalized = statusString.toLowerCase();
|
|
265736
|
-
if (normalized === "none" || normalized === "nostatus")
|
|
265737
|
-
return 0 /* NoStatus */;
|
|
265738
|
-
if (normalized === "lite" || normalized === "poplite")
|
|
265739
|
-
return 1 /* ProofOfPersonhoodLite */;
|
|
265740
|
-
if (normalized === "full" || normalized === "popfull")
|
|
265741
|
-
return 2 /* ProofOfPersonhoodFull */;
|
|
265742
|
-
throw new Error("Invalid status: use none, lite, or full");
|
|
265743
|
-
}
|
|
265744
|
-
|
|
265745
|
-
// src/cli/commands/register.ts
|
|
265746
|
-
function resolveTransferDestination(options2) {
|
|
265747
|
-
const legacy = options2.transferTo;
|
|
265748
|
-
const modern = options2.to;
|
|
265749
|
-
const destination = legacy ?? modern;
|
|
265750
|
-
if (options2.transfer === true && !destination) {
|
|
265751
|
-
throw new Error("Missing transfer destination: use --to <evm|ss58|label>");
|
|
265752
|
-
}
|
|
265753
|
-
if (options2.transfer === false && legacy) {
|
|
265754
|
-
return legacy;
|
|
265755
|
-
}
|
|
265756
|
-
return destination;
|
|
265757
|
-
}
|
|
265758
|
-
function classifyTransferDestination(destination) {
|
|
265759
|
-
if (isAddress(destination))
|
|
265760
|
-
return "evm";
|
|
265761
|
-
if (isValidSubstrateAddress(destination))
|
|
265762
|
-
return "substrate";
|
|
265763
|
-
return "label";
|
|
265764
|
-
}
|
|
265765
|
-
function isValidTransferDestination(destination) {
|
|
265766
|
-
const kind = classifyTransferDestination(destination);
|
|
265767
|
-
if (kind === "evm" || kind === "substrate")
|
|
265768
|
-
return true;
|
|
265769
|
-
const domainLabelPattern = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;
|
|
265770
|
-
return domainLabelPattern.test(destination) && destination.length >= 3 && destination.length <= 63;
|
|
265771
265376
|
}
|
|
265772
|
-
|
|
265773
|
-
|
|
265774
|
-
|
|
265775
|
-
|
|
265776
|
-
|
|
265777
|
-
return executeSubnameRegistration(options2);
|
|
265778
|
-
}
|
|
265779
|
-
const transferDestination = resolveTransferDestination(options2);
|
|
265780
|
-
if (transferDestination && !isValidTransferDestination(transferDestination)) {
|
|
265781
|
-
throw new Error("Invalid transfer destination: must be valid EVM address, Substrate address, or domain label");
|
|
265782
|
-
}
|
|
265783
|
-
const context = await prepareAssetHubContext(options2);
|
|
265784
|
-
const { clientWrapper, substrateAddress, signer, evmAddress } = context;
|
|
265785
|
-
const statusWasProvided = options2.__statusProvided === true;
|
|
265786
|
-
const popStatusConfig = statusWasProvided ? { mode: "set", status: parseProofOfPersonhoodStatus(options2.status ?? "none") } : { mode: "unchanged" };
|
|
265787
|
-
const label = options2.name ?? generateRandomLabel(popStatusConfig.mode === "set" ? popStatusConfig.status : 0 /* NoStatus */);
|
|
265788
|
-
console.log(source_default.gray(" Mode: ") + source_default.yellow(options2.governance ? "Governance registration" : "Regular registration"));
|
|
265789
|
-
console.log(source_default.gray(" Label: ") + source_default.cyan(label));
|
|
265790
|
-
console.log(source_default.gray(" Domain: ") + source_default.cyan(label + ".dot"));
|
|
265791
|
-
console.log(source_default.gray(" Transfer: ") + (transferDestination ? source_default.green("post-mint") : source_default.gray("none")));
|
|
265792
|
-
await step("Ensuring account mapped", async () => clientWrapper.ensureAccountMapped(substrateAddress, signer));
|
|
265793
|
-
if (options2.governance) {
|
|
265794
|
-
await executeGovernanceRegistration(clientWrapper, substrateAddress, signer, evmAddress, label, transferDestination, options2.commitmentBuffer);
|
|
265795
|
-
} else {
|
|
265796
|
-
await executeRegularRegistration(clientWrapper, substrateAddress, signer, evmAddress, label, popStatusConfig, options2.reverse ?? false, transferDestination, options2.commitmentBuffer);
|
|
265797
|
-
}
|
|
265798
|
-
console.log(`
|
|
265799
|
-
${source_default.bold.green("═══════════════════════════════════════")}`);
|
|
265800
|
-
console.log(`${source_default.bold.green(" ✓ Operation Complete ")}`);
|
|
265801
|
-
console.log(`${source_default.bold.green("═══════════════════════════════════════")}
|
|
265802
|
-
`);
|
|
265803
|
-
console.log(source_default.gray(" Domain: ") + source_default.cyan(label + ".dot"));
|
|
265804
|
-
}
|
|
265805
|
-
async function executeSubnameRegistration(options2) {
|
|
265806
|
-
if (!options2.name) {
|
|
265807
|
-
throw new Error("Missing subname: use --name <sublabel>");
|
|
265808
|
-
}
|
|
265809
|
-
if (!options2.parent) {
|
|
265810
|
-
throw new Error("Missing parent: use --parent <parentlabel>");
|
|
265811
|
-
}
|
|
265812
|
-
const context = await prepareAssetHubContext(options2);
|
|
265813
|
-
const { clientWrapper, substrateAddress, signer, evmAddress } = context;
|
|
265814
|
-
const sublabel = options2.name;
|
|
265815
|
-
const parentLabel = options2.parent;
|
|
265816
|
-
const ownerAddress = options2.owner ?? evmAddress;
|
|
265817
|
-
const fullName = `${sublabel}.${parentLabel}.dot`;
|
|
265818
|
-
console.log(source_default.bold(`
|
|
265819
|
-
▶ Subname Registration
|
|
265820
|
-
`));
|
|
265821
|
-
console.log(source_default.gray(" Subname: ") + source_default.cyan(fullName));
|
|
265822
|
-
console.log(source_default.gray(" Parent: ") + source_default.white(`${parentLabel}.dot`));
|
|
265823
|
-
console.log(source_default.gray(" Owner: ") + source_default.white(ownerAddress));
|
|
265824
|
-
await step("Ensuring account mapped", async () => clientWrapper.ensureAccountMapped(substrateAddress, signer));
|
|
265825
|
-
await registerSubnode(clientWrapper, substrateAddress, signer, sublabel, parentLabel, ownerAddress);
|
|
265826
|
-
console.log(`
|
|
265827
|
-
${source_default.bold.green("═══════════════════════════════════════")}`);
|
|
265828
|
-
console.log(`${source_default.bold.green(" ✓ Subname Registered ")}`);
|
|
265829
|
-
console.log(`${source_default.bold.green("═══════════════════════════════════════")}
|
|
265830
|
-
`);
|
|
265831
|
-
console.log(source_default.gray(" Domain: ") + source_default.cyan(fullName));
|
|
265832
|
-
}
|
|
265833
|
-
async function executeGovernanceRegistration(clientWrapper, substrateAddress, signer, evmAddress, label, transferDestination, commitmentBuffer) {
|
|
265834
|
-
console.log(source_default.bold(`
|
|
265835
|
-
\uD83C\uDFDB Governance registration (commit-reveal)
|
|
265836
|
-
`));
|
|
265837
|
-
validateGovernanceLabel(label);
|
|
265838
|
-
const classification = await step("Classifying name", async () => classifyDomainName(clientWrapper, substrateAddress, label));
|
|
265839
|
-
if (classification.requiredStatus !== 3 /* Reserved */) {
|
|
265840
|
-
throw new Error(`Governance name must classify as Reserved; got ${ProofOfPersonhoodStatus[classification.requiredStatus]}`);
|
|
265841
|
-
}
|
|
265842
|
-
await step("Checking availability", async () => ensureDomainNotRegistered(clientWrapper, substrateAddress, label));
|
|
265843
|
-
const { commitment, registration } = await step("Generating commitment", async () => generateCommitment(clientWrapper, substrateAddress, label, evmAddress, true));
|
|
265844
|
-
await step("Submitting commitment", async () => submitCommitment(clientWrapper, substrateAddress, signer, commitment));
|
|
265845
|
-
await step("Waiting commitment age", async () => waitForMinimumCommitmentAge(clientWrapper, substrateAddress, commitment, commitmentBuffer));
|
|
265846
|
-
await step("Finalizing registration", async () => finalizeGovernanceRegistration(clientWrapper, substrateAddress, signer, registration));
|
|
265847
|
-
await step("Verifying ownership", async () => verifyDomainOwnership(clientWrapper, substrateAddress, label, evmAddress));
|
|
265848
|
-
await step("Displaying store", async () => displayDeployedStore(clientWrapper, substrateAddress, evmAddress));
|
|
265849
|
-
await step("Ensuring store authorizations", async () => ensureStoreAuthorizations(clientWrapper, substrateAddress, signer, evmAddress));
|
|
265850
|
-
if (transferDestination) {
|
|
265851
|
-
const recipient = await step("Resolving recipient", async () => resolveTransferRecipient(clientWrapper, substrateAddress, transferDestination));
|
|
265852
|
-
await step("Transferring domain", async () => transferDomain(clientWrapper, substrateAddress, signer, evmAddress, recipient, label));
|
|
265853
|
-
await step("Verifying ownership", async () => verifyDomainOwnership(clientWrapper, substrateAddress, label, recipient));
|
|
265854
|
-
}
|
|
265855
|
-
}
|
|
265856
|
-
async function executeRegularRegistration(clientWrapper, substrateAddress, signer, evmAddress, label, popStatusConfig, enableReverseRecord, transferDestination, commitmentBuffer) {
|
|
265857
|
-
console.log(source_default.bold(`
|
|
265858
|
-
\uD83E\uDDFE Regular registration (commit-reveal)
|
|
265859
|
-
`));
|
|
265860
|
-
validateDomainLabel(label);
|
|
265861
|
-
const classification = await step("Classifying name", async () => classifyDomainName(clientWrapper, substrateAddress, label));
|
|
265862
|
-
if (popStatusConfig.mode === "set") {
|
|
265863
|
-
await step("Setting PoP status", async () => setUserProofOfPersonhoodStatus(clientWrapper, substrateAddress, signer, evmAddress, label, popStatusConfig.status));
|
|
265864
|
-
}
|
|
265865
|
-
await step("Checking availability", async () => ensureDomainNotRegistered(clientWrapper, substrateAddress, label));
|
|
265866
|
-
const { commitment, registration } = await step("Generating commitment", async () => generateCommitment(clientWrapper, substrateAddress, label, evmAddress, enableReverseRecord));
|
|
265867
|
-
await step("Submitting commitment", async () => submitCommitment(clientWrapper, substrateAddress, signer, commitment));
|
|
265868
|
-
await step("Waiting commitment age", async () => waitForMinimumCommitmentAge(clientWrapper, substrateAddress, commitment, commitmentBuffer));
|
|
265869
|
-
const pricing = await step("Pricing and eligibility", async () => getPriceAndValidateEligibility(clientWrapper, substrateAddress, label, evmAddress));
|
|
265870
|
-
await step("Finalizing registration", async () => finalizeRegularRegistration(clientWrapper, substrateAddress, signer, registration, pricing.priceWei));
|
|
265871
|
-
await step("Verifying ownership", async () => verifyDomainOwnership(clientWrapper, substrateAddress, label, evmAddress));
|
|
265872
|
-
await step("Displaying store", async () => displayDeployedStore(clientWrapper, substrateAddress, evmAddress));
|
|
265873
|
-
await step("Ensuring store authorizations", async () => ensureStoreAuthorizations(clientWrapper, substrateAddress, signer, evmAddress));
|
|
265874
|
-
if (transferDestination) {
|
|
265875
|
-
const recipient = await step("Resolving recipient", async () => resolveTransferRecipient(clientWrapper, substrateAddress, transferDestination));
|
|
265876
|
-
await step("Transferring domain", async () => transferDomain(clientWrapper, substrateAddress, signer, evmAddress, recipient, label));
|
|
265877
|
-
await step("Verifying ownership", async () => verifyDomainOwnership(clientWrapper, substrateAddress, label, recipient));
|
|
265878
|
-
}
|
|
265879
|
-
}
|
|
265880
|
-
|
|
265881
|
-
// src/cli/commands/lookup.ts
|
|
265882
|
-
function createClientWrapper(rpc) {
|
|
265883
|
-
const client = createClient3(getWsProvider(rpc)).getTypedApi(paseo_default);
|
|
265884
|
-
return new ReviveClientWrapper(client);
|
|
265885
|
-
}
|
|
265886
|
-
function getJsonFlag(command) {
|
|
265887
|
-
if (command && typeof command.optsWithGlobals === "function") {
|
|
265888
|
-
const options2 = command.optsWithGlobals();
|
|
265889
|
-
if (typeof options2?.json === "boolean")
|
|
265890
|
-
return options2.json;
|
|
265891
|
-
}
|
|
265892
|
-
const localOptions = command && typeof command.opts === "function" ? command.opts() : undefined;
|
|
265893
|
-
if (typeof localOptions?.json === "boolean")
|
|
265894
|
-
return localOptions.json;
|
|
265895
|
-
return process.argv.includes("--json");
|
|
265896
|
-
}
|
|
265897
|
-
function hasAnyAuthHint(opts) {
|
|
265898
|
-
return opts.mnemonic != null && String(opts.mnemonic).length > 0 || opts.keyUri != null && String(opts.keyUri).length > 0 || opts.keystorePath != null && String(opts.keystorePath).length > 0 || opts.account != null && String(opts.account).length > 0 || opts.password != null && String(opts.password).length > 0;
|
|
265899
|
-
}
|
|
265900
|
-
function withReadOnlyPasswordFallback(opts) {
|
|
265901
|
-
const passwordEnv = process.env.DOTNS_KEYSTORE_PASSWORD;
|
|
265902
|
-
if ((opts.password == null || String(opts.password).length === 0) && passwordEnv && passwordEnv.length > 0) {
|
|
265903
|
-
return { ...opts, password: passwordEnv };
|
|
265904
|
-
}
|
|
265905
|
-
return opts;
|
|
265906
|
-
}
|
|
265907
|
-
async function prepareReadOnlyContext(options2) {
|
|
265908
|
-
const rpc = resolveRpc(options2.rpc);
|
|
265909
|
-
const clientWrapper = await step(`Connecting RPC ${rpc}`, async () => createClientWrapper(rpc));
|
|
265910
|
-
const auth = await step("Resolving read-only account", async () => {
|
|
265911
|
-
if (hasAnyAuthHint(options2)) {
|
|
265912
|
-
const merged = withReadOnlyPasswordFallback(options2);
|
|
265913
|
-
const resolved2 = await resolveAuthSource(merged);
|
|
265914
|
-
return {
|
|
265915
|
-
source: resolved2.source,
|
|
265916
|
-
isKeyUri: resolved2.isKeyUri,
|
|
265917
|
-
resolvedFrom: resolved2.resolvedFrom,
|
|
265918
|
-
account: resolved2.account
|
|
265919
|
-
};
|
|
265920
|
-
}
|
|
265921
|
-
const resolved = await resolveAuthSourceReadOnly();
|
|
265922
|
-
return {
|
|
265923
|
-
source: resolved.source,
|
|
265924
|
-
isKeyUri: resolved.isKeyUri,
|
|
265925
|
-
resolvedFrom: resolved.resolvedFrom,
|
|
265926
|
-
account: resolved.account
|
|
265927
|
-
};
|
|
265928
|
-
});
|
|
265929
|
-
const keypair3 = await step("Loading keypair", async () => createAccountFromSource(auth.source, auth.isKeyUri));
|
|
265930
|
-
const evmAddress = await step("Resolving EVM address", async () => clientWrapper.getEvmAddress(keypair3.address));
|
|
265931
|
-
console.log(source_default.gray(`
|
|
265932
|
-
RPC: `) + source_default.white(rpc));
|
|
265933
|
-
console.log(source_default.gray(" Account: ") + source_default.white(keypair3.address));
|
|
265934
|
-
return { clientWrapper, account: { address: keypair3.address }, rpc, evmAddress };
|
|
265935
|
-
}
|
|
265936
|
-
async function resolveRecipientByKind(clientWrapper, substrateAddress, destination) {
|
|
265937
|
-
const kind = classifyTransferDestination(destination);
|
|
265938
|
-
switch (kind) {
|
|
265939
|
-
case "evm":
|
|
265940
|
-
return destination;
|
|
265941
|
-
case "substrate":
|
|
265942
|
-
return clientWrapper.getEvmAddress(destination);
|
|
265943
|
-
case "label":
|
|
265944
|
-
return resolveTransferRecipient(clientWrapper, substrateAddress, destination);
|
|
265945
|
-
}
|
|
265946
|
-
}
|
|
265947
|
-
function attachLookupCommands(root) {
|
|
265948
|
-
const lookupCommand = root.command("lookup").description("Lookup domain information");
|
|
265949
|
-
addAuthOptions(lookupCommand);
|
|
265950
|
-
const lookupNameCommand = lookupCommand.command("name [label]").description("Lookup comprehensive domain information").option("-n, --name <label>", "Domain label to lookup (alternative to positional argument)").option("--json", "Output result as JSON (suppresses all other output)", false);
|
|
265951
|
-
addAuthOptions(lookupNameCommand).action(async (positionalLabel, options2, cmd) => {
|
|
265377
|
+
function attachBulletinCommands(root) {
|
|
265378
|
+
const bulletinCommand = addReporterOption(root.command("bulletin").description("Bulletin storage utilities")).option("--json", "Write machine-readable JSON to stdout", false);
|
|
265379
|
+
addAuthOptions(bulletinCommand);
|
|
265380
|
+
const authorizeCommand = addReporterOption(bulletinCommand.command("authorize [address]").description("Authorize an account for Bulletin TransactionStorage").option("--bulletin-rpc <wsUrl>", "Bulletin WebSocket RPC endpoint", DEFAULT_BULLETIN_RPC).option("--transactions <count>", "Number of transactions to authorize", String(DEFAULT_AUTHORIZATION_TRANSACTIONS)).option("--bytes <count>", "Number of bytes to authorize", String(DEFAULT_AUTHORIZATION_BYTES)).option("--force", "Force re-authorization even if account appears already authorized", false).option("--json", "Write machine-readable JSON to stdout", false));
|
|
265381
|
+
addAuthOptions(authorizeCommand).action(async (positionalAddress, options2, command) => {
|
|
265952
265382
|
try {
|
|
265953
|
-
const
|
|
265954
|
-
|
|
265955
|
-
|
|
265956
|
-
|
|
265957
|
-
|
|
265958
|
-
const
|
|
265959
|
-
const
|
|
265960
|
-
|
|
265961
|
-
|
|
265962
|
-
|
|
265963
|
-
|
|
265964
|
-
|
|
265965
|
-
|
|
265966
|
-
|
|
265967
|
-
`));
|
|
265968
|
-
console.log(source_default.gray("
|
|
265969
|
-
console.log(source_default.gray("
|
|
265970
|
-
console.log(source_default.gray(
|
|
265971
|
-
|
|
265972
|
-
|
|
265383
|
+
const mergedOptions = getMergedOptions(command, options2);
|
|
265384
|
+
const jsonOutput = getJsonFlag(command);
|
|
265385
|
+
const reporterMode = resolveReporterMode(mergedOptions.reporter);
|
|
265386
|
+
const reporter = createCliReporter(mergedOptions.reporter);
|
|
265387
|
+
const onPhase = createPhaseHandler(reporter);
|
|
265388
|
+
const bulletinRpc = String(mergedOptions.bulletinRpc || DEFAULT_BULLETIN_RPC);
|
|
265389
|
+
const transactions = Number(mergedOptions.transactions || DEFAULT_AUTHORIZATION_TRANSACTIONS);
|
|
265390
|
+
const bytes = BigInt(mergedOptions.bytes || DEFAULT_AUTHORIZATION_BYTES);
|
|
265391
|
+
const force = Boolean(options2.force);
|
|
265392
|
+
const signerKeyUri = String(mergedOptions.keyUri || DEFAULT_SUDO_KEY_URI);
|
|
265393
|
+
const targetAddress = await resolveTargetAddress(positionalAddress, mergedOptions, reporterMode);
|
|
265394
|
+
const signerContext = await withBulletinHumanOutput(reporterMode, () => prepareContext({ keyUri: signerKeyUri, useBulletin: true }));
|
|
265395
|
+
if (!jsonOutput) {
|
|
265396
|
+
console.log(source_default.blue(`
|
|
265397
|
+
▶ Bulletin Authorize`));
|
|
265398
|
+
console.log(source_default.gray(" target: ") + source_default.cyan(targetAddress));
|
|
265399
|
+
console.log(source_default.gray(" rpc: ") + source_default.white(bulletinRpc));
|
|
265400
|
+
console.log(source_default.gray(" transactions: ") + source_default.white(transactions.toLocaleString()));
|
|
265401
|
+
console.log(source_default.gray(" bytes: ") + source_default.white(formatBytes(bytes)));
|
|
265402
|
+
console.log(source_default.gray(" signer: ") + source_default.yellow(signerKeyUri));
|
|
265973
265403
|
}
|
|
265974
|
-
|
|
265975
|
-
|
|
265976
|
-
|
|
265977
|
-
|
|
265978
|
-
|
|
265979
|
-
|
|
265404
|
+
await withBulletinHumanOutput(reporterMode, () => authorizeAccount({
|
|
265405
|
+
rpc: bulletinRpc,
|
|
265406
|
+
signer: signerContext.signer,
|
|
265407
|
+
targetAddress,
|
|
265408
|
+
transactions,
|
|
265409
|
+
bytes,
|
|
265410
|
+
force,
|
|
265411
|
+
onPhase
|
|
265412
|
+
}));
|
|
265980
265413
|
if (jsonOutput) {
|
|
265981
|
-
|
|
265414
|
+
const authStatus = await checkAuthorization(bulletinRpc, targetAddress);
|
|
265415
|
+
const expiresAt = expirationToISOString(authStatus.currentBlock, authStatus.expiration);
|
|
265416
|
+
writeBulletinJson({
|
|
265417
|
+
ok: true,
|
|
265418
|
+
target: targetAddress,
|
|
265419
|
+
rpc: bulletinRpc,
|
|
265420
|
+
transactions,
|
|
265421
|
+
bytes: bytes.toString(),
|
|
265422
|
+
expiresAt
|
|
265423
|
+
});
|
|
265982
265424
|
} else {
|
|
265983
265425
|
console.log(source_default.green(`
|
|
265984
|
-
✓ Complete
|
|
265426
|
+
✓ Authorization Complete`));
|
|
265427
|
+
console.log(source_default.gray(` The account can now upload to Bulletin.
|
|
265985
265428
|
`));
|
|
265986
265429
|
}
|
|
265987
265430
|
process.exit(0);
|
|
265988
265431
|
} catch (error2) {
|
|
265989
265432
|
const errorMessage = formatErrorMessage(error2);
|
|
265990
|
-
const jsonOutput = getJsonFlag(
|
|
265433
|
+
const jsonOutput = getJsonFlag(command);
|
|
265991
265434
|
if (jsonOutput) {
|
|
265992
|
-
|
|
265993
|
-
process.exit(1);
|
|
265435
|
+
writeBulletinJsonError(errorMessage);
|
|
265994
265436
|
}
|
|
265995
|
-
|
|
265996
|
-
|
|
265997
|
-
|
|
265998
|
-
process.exit(1);
|
|
265999
|
-
}
|
|
266000
|
-
});
|
|
266001
|
-
lookupCommand.option("-n, --name <label>", "Domain label to lookup").option("--json", "Output result as JSON (suppresses all other output)", false).action(async (options2, cmd) => {
|
|
266002
|
-
const subcommand = cmd.args?.[0];
|
|
266003
|
-
if (["name", "owner-of", "oo", "transfer"].includes(subcommand))
|
|
266004
|
-
return;
|
|
266005
|
-
if (options2.name) {
|
|
266006
|
-
try {
|
|
266007
|
-
const merged = { ...options2 ?? {}, ...getAuthOptions(cmd) };
|
|
266008
|
-
const jsonOutput = getJsonFlag(cmd);
|
|
266009
|
-
const { clientWrapper, account } = await maybeQuiet(jsonOutput, () => prepareReadOnlyContext(merged));
|
|
266010
|
-
if (!jsonOutput)
|
|
266011
|
-
console.log(source_default.bold(`
|
|
266012
|
-
▶ Domain Lookup
|
|
266013
|
-
`));
|
|
266014
|
-
const result = await maybeQuiet(jsonOutput, () => performDomainLookup(merged.name, account.address, clientWrapper));
|
|
266015
|
-
if (jsonOutput) {
|
|
266016
|
-
console.log(JSON.stringify(result));
|
|
266017
|
-
} else {
|
|
266018
|
-
console.log(source_default.green(`
|
|
266019
|
-
✓ Complete
|
|
265437
|
+
if (errorMessage.includes("AlreadyAuthorized")) {
|
|
265438
|
+
console.log(source_default.yellow(`
|
|
265439
|
+
⚠ Account is already authorized
|
|
266020
265440
|
`));
|
|
266021
|
-
}
|
|
266022
265441
|
process.exit(0);
|
|
266023
|
-
}
|
|
266024
|
-
|
|
266025
|
-
const jsonOutput = getJsonFlag(cmd);
|
|
266026
|
-
if (jsonOutput) {
|
|
266027
|
-
console.error(JSON.stringify({ error: errorMessage }));
|
|
266028
|
-
process.exit(1);
|
|
266029
|
-
}
|
|
265442
|
+
}
|
|
265443
|
+
if (errorMessage.includes("BadOrigin")) {
|
|
266030
265444
|
console.error(source_default.red(`
|
|
266031
|
-
✗
|
|
265445
|
+
✗ Authorization failed — insufficient privileges`));
|
|
265446
|
+
console.error(source_default.yellow(" The signer does not have Authorizer privileges on this chain."));
|
|
265447
|
+
console.error(source_default.gray(` Override with --key-uri if needed.
|
|
265448
|
+
`));
|
|
265449
|
+
process.exit(1);
|
|
265450
|
+
}
|
|
265451
|
+
if (errorMessage.includes("not applied")) {
|
|
265452
|
+
console.error(source_default.red(`
|
|
265453
|
+
✗ ${errorMessage}`));
|
|
265454
|
+
console.error(source_default.gray(` Override with --key-uri if needed.
|
|
266032
265455
|
`));
|
|
266033
265456
|
process.exit(1);
|
|
266034
265457
|
}
|
|
265458
|
+
console.error(source_default.red(`
|
|
265459
|
+
✗ Error: ${errorMessage}
|
|
265460
|
+
`));
|
|
265461
|
+
process.exit(1);
|
|
266035
265462
|
}
|
|
266036
265463
|
});
|
|
266037
|
-
const
|
|
266038
|
-
addAuthOptions(
|
|
265464
|
+
const uploadCommand = addReporterOption(bulletinCommand.command("upload <path>").description("Upload a file or directory to Bulletin and print the resulting CID").option("--bulletin-rpc <wsUrl>", "Bulletin WebSocket RPC endpoint", DEFAULT_BULLETIN_RPC).option("--chunk-size <bytes>", "Chunk size for large uploads (clamped to 256 KB–2 MB)", String(DEFAULT_CHUNK_SIZE_BYTES)).option("--max-retries <n>", "Retry transient upload failures (default: 5, capped at 20)", String(DEFAULT_UPLOAD_MAX_RETRIES)).option("--force-chunked", "Force chunked upload (DAG-PB)", false).option("--concurrency <n>", "Adaptive scheduler max window (default: 16, max: 64)", "16").option("--print-contenthash", "Also print 0x-prefixed IPFS contenthash for the CID", false).option("--resume", "Resume a previously interrupted upload", false).option("--profile-upload", "Enable upload profiling and write a JSON report", false).option("--profile-output <path>", "Path to write upload profiling JSON report").option("--no-history", "Do not save upload to history", true).option("--cache", "Write the CID to the user's on-chain Store after upload", false).option("--json", "Write machine-readable JSON to stdout", false));
|
|
265465
|
+
addAuthOptions(uploadCommand).action(async (inputPath, options2, command) => {
|
|
266039
265466
|
try {
|
|
266040
|
-
const
|
|
266041
|
-
const jsonOutput = getJsonFlag(
|
|
266042
|
-
const
|
|
266043
|
-
|
|
266044
|
-
|
|
266045
|
-
|
|
266046
|
-
|
|
266047
|
-
|
|
266048
|
-
if (jsonOutput) {
|
|
266049
|
-
console.log(JSON.stringify(result));
|
|
266050
|
-
} else {
|
|
266051
|
-
console.log(source_default.green(`
|
|
266052
|
-
✓ Complete
|
|
266053
|
-
`));
|
|
266054
|
-
}
|
|
266055
|
-
process.exit(0);
|
|
266056
|
-
} catch (error2) {
|
|
266057
|
-
const errorMessage = formatErrorMessage(error2);
|
|
266058
|
-
const jsonOutput = getJsonFlag(cmd);
|
|
266059
|
-
if (jsonOutput) {
|
|
266060
|
-
console.error(JSON.stringify({ error: errorMessage }));
|
|
266061
|
-
process.exit(1);
|
|
265467
|
+
const mergedOptions = getMergedOptions(command, options2);
|
|
265468
|
+
const jsonOutput = getJsonFlag(command);
|
|
265469
|
+
const reporterMode = resolveReporterMode(mergedOptions.reporter);
|
|
265470
|
+
const reporter = createCliReporter(mergedOptions.reporter);
|
|
265471
|
+
const onPhase = createPhaseHandler(reporter);
|
|
265472
|
+
const onRetry = createRetryHandler(reporter);
|
|
265473
|
+
if (mergedOptions.mnemonic && mergedOptions.keyUri) {
|
|
265474
|
+
throw new Error("Cannot specify both --mnemonic and --key-uri");
|
|
266062
265475
|
}
|
|
266063
|
-
|
|
266064
|
-
|
|
266065
|
-
|
|
266066
|
-
|
|
266067
|
-
|
|
266068
|
-
|
|
266069
|
-
|
|
266070
|
-
|
|
266071
|
-
|
|
266072
|
-
const
|
|
266073
|
-
const
|
|
266074
|
-
|
|
266075
|
-
if (
|
|
266076
|
-
|
|
265476
|
+
await cleanupStaleManifests();
|
|
265477
|
+
const validatedPath = await withBulletinHumanOutput(reporterMode, () => validateAndReadPath(inputPath, onPhase));
|
|
265478
|
+
const { bytes, isDirectory, resolvedPath, fileSize, fileMtimeMs } = validatedPath;
|
|
265479
|
+
const bulletinRpc = String(mergedOptions.bulletinRpc || DEFAULT_BULLETIN_RPC);
|
|
265480
|
+
const chunkSizeBytes = clampChunkSizeBytes(Number(mergedOptions.chunkSize || DEFAULT_CHUNK_SIZE_BYTES));
|
|
265481
|
+
const maxRetries = normalizeUploadMaxRetries(mergedOptions.maxRetries);
|
|
265482
|
+
const concurrency = Math.max(1, Math.min(64, Math.floor(Number(mergedOptions.concurrency || 16))));
|
|
265483
|
+
const resume = Boolean(mergedOptions.resume);
|
|
265484
|
+
const profileUpload = Boolean(mergedOptions.profileUpload);
|
|
265485
|
+
const shouldUseChunkedUpload = !isDirectory;
|
|
265486
|
+
const effectiveFileSize = isDirectory ? 0 : fileSize ?? bytes.length;
|
|
265487
|
+
let resumedBlocks;
|
|
265488
|
+
if (resume && shouldUseChunkedUpload) {
|
|
265489
|
+
const resolvedFileMtimeMs = fileMtimeMs ?? (await filesystem2.stat(resolvedPath)).mtimeMs;
|
|
265490
|
+
const manifestLoadResult = await loadManifestForResume({
|
|
265491
|
+
inputPath: resolvedPath,
|
|
265492
|
+
fileSize: effectiveFileSize,
|
|
265493
|
+
fileMtimeMs: resolvedFileMtimeMs,
|
|
265494
|
+
chunkSize: chunkSizeBytes
|
|
265495
|
+
});
|
|
265496
|
+
if (manifestLoadResult.manifest && manifestLoadResult.manifest.completedBlocks.length > 0) {
|
|
265497
|
+
resumedBlocks = completedBlocksFromManifest(manifestLoadResult.manifest);
|
|
265498
|
+
reporter.warn(`resuming: ${manifestLoadResult.manifest.completedBlocks.length} blocks already uploaded`);
|
|
265499
|
+
} else if (manifestLoadResult.staleManifest) {
|
|
265500
|
+
reporter.warn("resume notice: file fingerprint changed, starting a fresh upload manifest");
|
|
265501
|
+
await deleteManifest(manifestLoadResult.staleManifest);
|
|
265502
|
+
}
|
|
266077
265503
|
}
|
|
266078
|
-
const
|
|
266079
|
-
|
|
266080
|
-
|
|
265504
|
+
const context = await withBulletinHumanOutput(reporterMode, () => prepareContext({ ...mergedOptions, useBulletin: true }));
|
|
265505
|
+
const authInfo = await withBulletinHumanOutput(reporterMode, () => ensureAccountAuthorized(bulletinRpc, context.substrateAddress));
|
|
265506
|
+
const profileOutputOverride = mergedOptions.profileOutput ? String(mergedOptions.profileOutput) : undefined;
|
|
265507
|
+
const profiler = profileUpload ? createUploadProfiler({
|
|
265508
|
+
sourcePath: resolvedPath,
|
|
265509
|
+
sourceSizeBytes: effectiveFileSize,
|
|
265510
|
+
chunkSizeBytes: shouldUseChunkedUpload ? chunkSizeBytes : Math.max(1, effectiveFileSize),
|
|
265511
|
+
rpc: bulletinRpc,
|
|
265512
|
+
initialConcurrency: shouldUseChunkedUpload ? 1 : 1,
|
|
265513
|
+
maxConcurrency: shouldUseChunkedUpload ? concurrency : 1,
|
|
265514
|
+
outputPath: profileOutputOverride,
|
|
265515
|
+
jsonOutput
|
|
265516
|
+
}) : undefined;
|
|
265517
|
+
const totalChunks = shouldUseChunkedUpload ? Math.ceil(effectiveFileSize / chunkSizeBytes) : undefined;
|
|
265518
|
+
const chunkedMonitor = shouldUseChunkedUpload && totalChunks ? createChunkedUploadMonitor(reporter, onPhase, effectiveFileSize, chunkSizeBytes, totalChunks) : null;
|
|
265519
|
+
const performUpload = async () => {
|
|
265520
|
+
if (isDirectory) {
|
|
265521
|
+
const result2 = await storeDirectory(bulletinRpc, context.signer, resolvedPath, {
|
|
265522
|
+
concurrency,
|
|
265523
|
+
accountAddress: context.substrateAddress,
|
|
265524
|
+
maxRetries,
|
|
265525
|
+
onPhase,
|
|
265526
|
+
onRetry,
|
|
265527
|
+
waitForFinalization: false
|
|
265528
|
+
});
|
|
265529
|
+
return { cid: result2.cid, size: 0 };
|
|
265530
|
+
}
|
|
265531
|
+
if (shouldUseChunkedUpload) {
|
|
265532
|
+
const result2 = await uploadChunkedBlocks(bulletinRpc, context.signer, resolvedPath, chunkSizeBytes, effectiveFileSize, context.substrateAddress, {
|
|
265533
|
+
completedBlocks: resumedBlocks,
|
|
265534
|
+
concurrency,
|
|
265535
|
+
maxRetries,
|
|
265536
|
+
onPhase,
|
|
265537
|
+
onRetry,
|
|
265538
|
+
onSchedulerState: (state3) => {
|
|
265539
|
+
profiler?.onSchedulerState(state3);
|
|
265540
|
+
chunkedMonitor?.onSchedulerState(state3);
|
|
265541
|
+
},
|
|
265542
|
+
onWave: (wave) => {
|
|
265543
|
+
profiler?.onWave(wave);
|
|
265544
|
+
chunkedMonitor?.onWave(wave);
|
|
265545
|
+
}
|
|
265546
|
+
});
|
|
265547
|
+
return { cid: result2, size: effectiveFileSize };
|
|
265548
|
+
}
|
|
265549
|
+
const result = await uploadSingleBlock(bulletinRpc, context.signer, bytes, {
|
|
265550
|
+
maxRetries,
|
|
265551
|
+
onPhase,
|
|
265552
|
+
onRetry
|
|
265553
|
+
});
|
|
265554
|
+
return { cid: result, size: bytes.length };
|
|
265555
|
+
};
|
|
265556
|
+
let cid;
|
|
265557
|
+
let uploadSize;
|
|
265558
|
+
let profileReportPath;
|
|
265559
|
+
let profileReport;
|
|
265560
|
+
const uploadStartedAtMs = Date.now();
|
|
265561
|
+
const uploadStartedAtIso = new Date(uploadStartedAtMs).toISOString();
|
|
265562
|
+
const pathBasename = resolvedPath.split("/").pop() ?? resolvedPath;
|
|
265563
|
+
if (authInfo?.expiration && authInfo.currentBlock) {
|
|
265564
|
+
reporter.detail(`auth: valid (expires ${formatExpirationDisplay(authInfo.currentBlock, authInfo.expiration)})`);
|
|
266081
265565
|
}
|
|
266082
|
-
const context = await maybeQuiet(jsonOutput, () => prepareAssetHubContext(merged));
|
|
266083
|
-
const { clientWrapper, substrateAddress, signer, evmAddress } = context;
|
|
266084
265566
|
if (!jsonOutput) {
|
|
266085
|
-
|
|
266086
|
-
|
|
266087
|
-
`));
|
|
266088
|
-
|
|
266089
|
-
|
|
265567
|
+
if (isDirectory) {
|
|
265568
|
+
console.log(source_default.blue(`
|
|
265569
|
+
▶ Uploading directory: ${pathBasename}`));
|
|
265570
|
+
console.log(source_default.gray(" path: ") + source_default.white(resolvedPath));
|
|
265571
|
+
console.log(source_default.gray(" rpc: ") + source_default.white(bulletinRpc));
|
|
265572
|
+
console.log(source_default.gray(" concurrency: ") + source_default.white(`${concurrency}x parallel waves`));
|
|
265573
|
+
} else if (shouldUseChunkedUpload) {
|
|
265574
|
+
console.log(source_default.blue(`
|
|
265575
|
+
▶ Uploading file: ${pathBasename} (${formatBytes(effectiveFileSize)})`));
|
|
265576
|
+
console.log(source_default.gray(" path: ") + source_default.white(resolvedPath));
|
|
265577
|
+
console.log(source_default.gray(" rpc: ") + source_default.white(bulletinRpc));
|
|
265578
|
+
console.log(source_default.gray(" mode: ") + source_default.white(`chunked (${totalChunks} × ${formatBytes(chunkSizeBytes)}, adaptive window 1..${concurrency})`));
|
|
265579
|
+
} else {
|
|
265580
|
+
console.log(source_default.blue(`
|
|
265581
|
+
▶ Uploading file: ${pathBasename} (${formatBytes(bytes.length)})`));
|
|
265582
|
+
console.log(source_default.gray(" path: ") + source_default.white(resolvedPath));
|
|
265583
|
+
console.log(source_default.gray(" rpc: ") + source_default.white(bulletinRpc));
|
|
265584
|
+
console.log(source_default.gray(" mode: ") + source_default.white("single block"));
|
|
265585
|
+
}
|
|
266090
265586
|
}
|
|
266091
|
-
|
|
266092
|
-
|
|
266093
|
-
|
|
266094
|
-
|
|
265587
|
+
try {
|
|
265588
|
+
const uploadResult = await withBulletinHumanOutput(reporterMode, performUpload);
|
|
265589
|
+
cid = uploadResult.cid;
|
|
265590
|
+
uploadSize = uploadResult.size;
|
|
265591
|
+
} finally {
|
|
265592
|
+
chunkedMonitor?.stop();
|
|
265593
|
+
}
|
|
265594
|
+
const uploadFinishedAtMs = Date.now();
|
|
265595
|
+
const uploadFinishedAtIso = new Date(uploadFinishedAtMs).toISOString();
|
|
265596
|
+
const totalUploadTimeMs = Math.max(1, uploadFinishedAtMs - uploadStartedAtMs);
|
|
265597
|
+
const totalUploadTimeSeconds = totalUploadTimeMs / 1000;
|
|
265598
|
+
if (profiler) {
|
|
265599
|
+
const finalizedProfile = await profiler.finalize(cid, profileOutputOverride);
|
|
265600
|
+
profileReport = finalizedProfile.report;
|
|
265601
|
+
profileReportPath = finalizedProfile.outputPath;
|
|
265602
|
+
}
|
|
265603
|
+
onPhase({
|
|
265604
|
+
phase: "verify",
|
|
265605
|
+
state: "start",
|
|
265606
|
+
message: "Verifying content on Bulletin P2P..."
|
|
265607
|
+
});
|
|
265608
|
+
let verified = false;
|
|
265609
|
+
try {
|
|
265610
|
+
const p2pResult = await verifyCidViaP2P(cid);
|
|
265611
|
+
if (p2pResult.resolvable) {
|
|
265612
|
+
onPhase({ phase: "verify", state: "success", message: "Content verified via P2P" });
|
|
265613
|
+
verified = true;
|
|
265614
|
+
}
|
|
265615
|
+
} catch {}
|
|
265616
|
+
if (!verified) {
|
|
265617
|
+
onPhase({
|
|
265618
|
+
phase: "verify",
|
|
265619
|
+
state: "update",
|
|
265620
|
+
message: "P2P unavailable, checking IPFS gateways..."
|
|
265621
|
+
});
|
|
265622
|
+
const gatewayResults = await verifyCidWithMultipleGateways(cid);
|
|
265623
|
+
const resolvable = Array.from(gatewayResults.values()).some((r2) => r2.resolvable);
|
|
265624
|
+
if (resolvable) {
|
|
265625
|
+
onPhase({
|
|
265626
|
+
phase: "verify",
|
|
265627
|
+
state: "success",
|
|
265628
|
+
message: "Content verified via IPFS gateway"
|
|
265629
|
+
});
|
|
265630
|
+
} else {
|
|
265631
|
+
onPhase({
|
|
265632
|
+
phase: "verify",
|
|
265633
|
+
state: "warning",
|
|
265634
|
+
message: "Content not yet resolvable — it may still be propagating"
|
|
265635
|
+
});
|
|
265636
|
+
}
|
|
265637
|
+
}
|
|
265638
|
+
const contenthash = generateContenthash(cid);
|
|
265639
|
+
const previewUrl = getPreviewUrl({
|
|
265640
|
+
cid,
|
|
265641
|
+
path: resolvedPath,
|
|
265642
|
+
type: isDirectory ? "directory" : "file",
|
|
265643
|
+
size: uploadSize,
|
|
265644
|
+
timestamp: ""
|
|
265645
|
+
});
|
|
266095
265646
|
if (jsonOutput) {
|
|
266096
|
-
|
|
266097
|
-
|
|
266098
|
-
|
|
266099
|
-
|
|
266100
|
-
|
|
266101
|
-
|
|
266102
|
-
|
|
265647
|
+
const authExpiresAt = expirationToISOString(authInfo?.currentBlock, authInfo?.expiration);
|
|
265648
|
+
writeBulletinJson({
|
|
265649
|
+
cid,
|
|
265650
|
+
contenthash: `0x${contenthash}`,
|
|
265651
|
+
preview: previewUrl,
|
|
265652
|
+
path: resolvedPath,
|
|
265653
|
+
type: isDirectory ? "directory" : "file",
|
|
265654
|
+
size: uploadSize,
|
|
265655
|
+
authorizationExpiresAt: authExpiresAt,
|
|
265656
|
+
uploadStartedAtIso,
|
|
265657
|
+
uploadFinishedAtIso,
|
|
265658
|
+
totalUploadTimeMs,
|
|
265659
|
+
totalUploadTimeSeconds
|
|
265660
|
+
});
|
|
266103
265661
|
} else {
|
|
265662
|
+
console.log(source_default.gray(`
|
|
265663
|
+
cid: `) + source_default.cyan(cid));
|
|
265664
|
+
console.log(source_default.gray(" preview: ") + source_default.blue(previewUrl));
|
|
265665
|
+
console.log(source_default.gray(" total time: ") + source_default.white(formatDuration(totalUploadTimeSeconds)));
|
|
265666
|
+
if (mergedOptions.printContenthash) {
|
|
265667
|
+
console.log(source_default.gray(" contenthash: ") + source_default.white(`0x${contenthash}`));
|
|
265668
|
+
}
|
|
265669
|
+
if (profileReportPath && profileReport) {
|
|
265670
|
+
console.log(source_default.gray(" profile: ") + source_default.white(profileReportPath));
|
|
265671
|
+
console.log(source_default.gray(" throughput: ") + source_default.white(`${formatBytes(profileReport.summary.throughputBytesPerSecond)}/s`));
|
|
265672
|
+
console.log(source_default.gray(" peak heap: ") + source_default.white(formatBytes(profileReport.summary.peakHeapUsed)));
|
|
265673
|
+
}
|
|
266104
265674
|
console.log(source_default.green(`
|
|
266105
|
-
✓ Complete
|
|
265675
|
+
✓ Upload Complete
|
|
266106
265676
|
`));
|
|
266107
265677
|
}
|
|
266108
|
-
|
|
266109
|
-
|
|
266110
|
-
|
|
266111
|
-
|
|
266112
|
-
|
|
266113
|
-
|
|
266114
|
-
|
|
266115
|
-
|
|
266116
|
-
|
|
265678
|
+
if (options2.cache) {
|
|
265679
|
+
onPhase({
|
|
265680
|
+
phase: "cache",
|
|
265681
|
+
state: "start",
|
|
265682
|
+
message: "Saving CID to on-chain Store..."
|
|
265683
|
+
});
|
|
265684
|
+
try {
|
|
265685
|
+
const { cacheCidToStore: cacheCidToStore2 } = await Promise.resolve().then(() => (init_storeManagement(), exports_storeManagement));
|
|
265686
|
+
const { createClient: createClient4 } = await Promise.resolve().then(() => (init_esm10(), exports_esm2));
|
|
265687
|
+
const { getWsProvider: getWsProvider2 } = await Promise.resolve().then(() => (init_ws_provider(), exports_ws_provider));
|
|
265688
|
+
const { paseo } = await Promise.resolve().then(() => (init_dist(), exports_dist));
|
|
265689
|
+
const { ReviveClientWrapper: ReviveClientWrapper2 } = await Promise.resolve().then(() => (init_polkadotClient(), exports_polkadotClient));
|
|
265690
|
+
const { resolveRpc: resolveRpc2 } = await Promise.resolve().then(() => (init_env(), exports_env));
|
|
265691
|
+
const rpc = resolveRpc2(process.env.DOTNS_RPC);
|
|
265692
|
+
const typedApi = createClient4(getWsProvider2(rpc)).getTypedApi(paseo);
|
|
265693
|
+
const clientWrapper = new ReviveClientWrapper2(typedApi);
|
|
265694
|
+
const evmAddress = await clientWrapper.getEvmAddress(context.substrateAddress);
|
|
265695
|
+
await cacheCidToStore2({
|
|
265696
|
+
cid,
|
|
265697
|
+
clientWrapper,
|
|
265698
|
+
signer: context.signer,
|
|
265699
|
+
substrateAddress: context.substrateAddress,
|
|
265700
|
+
evmAddress
|
|
265701
|
+
});
|
|
265702
|
+
onPhase({ phase: "cache", state: "success", message: "CID cached to Store" });
|
|
265703
|
+
} catch (cacheError) {
|
|
265704
|
+
const msg = formatErrorMessage(cacheError);
|
|
265705
|
+
let reason;
|
|
265706
|
+
if (/insufficient|balance/i.test(msg)) {
|
|
265707
|
+
reason = "insufficient PAS balance on Asset Hub — fund the account and retry with --cache";
|
|
265708
|
+
} else if (/no store deployed|store not deployed/i.test(msg)) {
|
|
265709
|
+
reason = "no Store deployed — register a domain first or deploy a Store manually";
|
|
265710
|
+
} else if (/not authorized|unauthorized/i.test(msg)) {
|
|
265711
|
+
reason = "Store not authorised for writes — run dotns store ensure-auth";
|
|
265712
|
+
} else {
|
|
265713
|
+
reason = msg;
|
|
265714
|
+
}
|
|
265715
|
+
onPhase({
|
|
265716
|
+
phase: "cache",
|
|
265717
|
+
state: "warning",
|
|
265718
|
+
message: `Store caching skipped: ${reason}`
|
|
265719
|
+
});
|
|
265720
|
+
}
|
|
265721
|
+
}
|
|
265722
|
+
if (mergedOptions.history !== false) {
|
|
265723
|
+
await addUploadRecord({
|
|
265724
|
+
cid,
|
|
265725
|
+
path: resolvedPath,
|
|
265726
|
+
type: isDirectory ? "directory" : "file",
|
|
265727
|
+
size: uploadSize
|
|
265728
|
+
});
|
|
265729
|
+
}
|
|
265730
|
+
process.exit(0);
|
|
265731
|
+
} catch (error2) {
|
|
265732
|
+
const errorMessage = formatErrorMessage(error2);
|
|
265733
|
+
const jsonOutput = getJsonFlag(command);
|
|
265734
|
+
if (jsonOutput) {
|
|
265735
|
+
writeBulletinJsonError(errorMessage);
|
|
265736
|
+
}
|
|
265737
|
+
console.error(source_default.red(`
|
|
266117
265738
|
✗ Error: ${errorMessage}
|
|
266118
265739
|
`));
|
|
266119
265740
|
process.exit(1);
|
|
266120
265741
|
}
|
|
266121
265742
|
});
|
|
266122
|
-
|
|
266123
|
-
|
|
266124
|
-
|
|
266125
|
-
|
|
266126
|
-
|
|
266127
|
-
|
|
266128
|
-
|
|
266129
|
-
|
|
266130
|
-
|
|
266131
|
-
|
|
266132
|
-
|
|
266133
|
-
|
|
266134
|
-
|
|
266135
|
-
|
|
266136
|
-
|
|
266137
|
-
|
|
266138
|
-
|
|
266139
|
-
|
|
265743
|
+
const statusCommand = addReporterOption(bulletinCommand.command("status [address]").description("Check authorization status for an account on Bulletin").option("--bulletin-rpc <wsUrl>", "Bulletin WebSocket RPC endpoint", DEFAULT_BULLETIN_RPC).option("--json", "Write machine-readable JSON to stdout", false));
|
|
265744
|
+
addAuthOptions(statusCommand).action(async (positionalAddress, options2, command) => {
|
|
265745
|
+
try {
|
|
265746
|
+
const mergedOptions = getMergedOptions(command, options2);
|
|
265747
|
+
const jsonOutput = getJsonFlag(command);
|
|
265748
|
+
const reporterMode = resolveReporterMode(mergedOptions.reporter);
|
|
265749
|
+
const reporter = createCliReporter(mergedOptions.reporter);
|
|
265750
|
+
const bulletinRpc = String(mergedOptions.bulletinRpc || DEFAULT_BULLETIN_RPC);
|
|
265751
|
+
const targetAddress = await resolveTargetAddress(positionalAddress, mergedOptions, reporterMode);
|
|
265752
|
+
const statusTask = reporter.task("Checking authorization");
|
|
265753
|
+
const authStatus = await checkAuthorization(bulletinRpc, targetAddress);
|
|
265754
|
+
statusTask.succeed("Authorization status read");
|
|
265755
|
+
if (jsonOutput) {
|
|
265756
|
+
writeBulletinJson({
|
|
265757
|
+
address: targetAddress,
|
|
265758
|
+
rpc: bulletinRpc,
|
|
265759
|
+
authorized: authStatus.authorized,
|
|
265760
|
+
expired: authStatus.expired ?? false,
|
|
265761
|
+
transactions: authStatus.transactions ?? 0,
|
|
265762
|
+
bytes: (authStatus.bytes ?? BigInt(0)).toString(),
|
|
265763
|
+
expiresAt: expirationToISOString(authStatus.currentBlock, authStatus.expiration)
|
|
265764
|
+
});
|
|
265765
|
+
} else {
|
|
265766
|
+
console.log(source_default.blue(`
|
|
265767
|
+
▶ Bulletin Authorization Status`));
|
|
265768
|
+
console.log(source_default.gray(" account: ") + source_default.cyan(targetAddress));
|
|
265769
|
+
console.log(source_default.gray(" rpc: ") + source_default.white(bulletinRpc));
|
|
265770
|
+
if (!authStatus.authorized) {
|
|
265771
|
+
console.log(source_default.gray(" status: ") + source_default.red("not authorized"));
|
|
265772
|
+
console.log(source_default.gray(`
|
|
265773
|
+
Authorize with: dotns bulletin authorize ` + targetAddress + `
|
|
265774
|
+
`));
|
|
265775
|
+
} else {
|
|
265776
|
+
const isExpired = authStatus.expired;
|
|
265777
|
+
const dateDisplay = formatExpirationDisplay(authStatus.currentBlock, authStatus.expiration);
|
|
265778
|
+
console.log(source_default.gray(" status: ") + (isExpired ? source_default.red("expired") : source_default.green("authorized")));
|
|
265779
|
+
console.log(source_default.gray(isExpired ? " expired: " : " expires: ") + (isExpired ? source_default.red(dateDisplay) : source_default.white(dateDisplay)));
|
|
265780
|
+
console.log(source_default.gray(" transactions: ") + source_default.white((authStatus.transactions ?? 0).toLocaleString()));
|
|
265781
|
+
console.log(source_default.gray(" bytes: ") + source_default.white(formatBytes(authStatus.bytes ?? BigInt(0))));
|
|
265782
|
+
if (isExpired) {
|
|
265783
|
+
console.log(source_default.gray(`
|
|
265784
|
+
Re-authorize with: dotns bulletin authorize ` + targetAddress + `
|
|
265785
|
+
`));
|
|
265786
|
+
} else {
|
|
265787
|
+
console.log();
|
|
265788
|
+
}
|
|
266140
265789
|
}
|
|
266141
265790
|
}
|
|
266142
|
-
|
|
266143
|
-
|
|
266144
|
-
|
|
266145
|
-
|
|
266146
|
-
|
|
266147
|
-
|
|
266148
|
-
|
|
266149
|
-
|
|
266150
|
-
}
|
|
266151
|
-
|
|
266152
|
-
|
|
266153
|
-
}
|
|
266154
|
-
function buildDefaultProfileOutputPath(sourcePath, fingerprint) {
|
|
266155
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
266156
|
-
const basename = path9.basename(sourcePath).replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
266157
|
-
return path9.join(os11.homedir(), ".dotns", "upload-profiles", `${timestamp}-${basename}-${fingerprint}.json`);
|
|
266158
|
-
}
|
|
266159
|
-
function createUploadProfiler(options2) {
|
|
266160
|
-
const startedAtMs = Date.now();
|
|
266161
|
-
const startedAtIso = new Date(startedAtMs).toISOString();
|
|
266162
|
-
let latestSchedulerState = {
|
|
266163
|
-
timestampMs: startedAtMs,
|
|
266164
|
-
window: Math.max(1, options2.initialConcurrency),
|
|
266165
|
-
inFlightBytes: 0,
|
|
266166
|
-
inFlightChunks: 0,
|
|
266167
|
-
completedChunks: 0,
|
|
266168
|
-
retries: 0
|
|
266169
|
-
};
|
|
266170
|
-
const samples = [];
|
|
266171
|
-
const waves = [];
|
|
266172
|
-
const captureSample = () => {
|
|
266173
|
-
const usage = process.memoryUsage();
|
|
266174
|
-
samples.push({
|
|
266175
|
-
timestampMs: Date.now(),
|
|
266176
|
-
heapUsed: usage.heapUsed,
|
|
266177
|
-
rss: usage.rss,
|
|
266178
|
-
arrayBuffers: usage.arrayBuffers,
|
|
266179
|
-
external: usage.external,
|
|
266180
|
-
inFlightBytes: latestSchedulerState.inFlightBytes,
|
|
266181
|
-
inFlightChunks: latestSchedulerState.inFlightChunks,
|
|
266182
|
-
window: latestSchedulerState.window,
|
|
266183
|
-
completed: latestSchedulerState.completedChunks,
|
|
266184
|
-
retries: latestSchedulerState.retries
|
|
266185
|
-
});
|
|
266186
|
-
};
|
|
266187
|
-
captureSample();
|
|
266188
|
-
const timer4 = setInterval(captureSample, PROFILE_SAMPLE_INTERVAL_MS);
|
|
266189
|
-
timer4.unref?.();
|
|
266190
|
-
const summarizeAndWrite = async (finalCid, overrideOutputPath) => {
|
|
266191
|
-
clearInterval(timer4);
|
|
266192
|
-
captureSample();
|
|
266193
|
-
const finishedAtMs = Date.now();
|
|
266194
|
-
const finishedAtIso = new Date(finishedAtMs).toISOString();
|
|
266195
|
-
const totalUploadTimeMs = Math.max(1, finishedAtMs - startedAtMs);
|
|
266196
|
-
const throughputBytesPerSecond = options2.sourceSizeBytes / totalUploadTimeMs * 1000;
|
|
266197
|
-
const peakHeapUsed = Math.max(...samples.map((sample) => sample.heapUsed));
|
|
266198
|
-
const peakRss = Math.max(...samples.map((sample) => sample.rss));
|
|
266199
|
-
const peakArrayBuffers = Math.max(...samples.map((sample) => sample.arrayBuffers));
|
|
266200
|
-
const peakExternal = Math.max(...samples.map((sample) => sample.external));
|
|
266201
|
-
const maxWindowReached = Math.max(...samples.map((sample) => sample.window));
|
|
266202
|
-
const report = {
|
|
266203
|
-
meta: {
|
|
266204
|
-
sourcePath: options2.sourcePath,
|
|
266205
|
-
sourceSizeBytes: options2.sourceSizeBytes,
|
|
266206
|
-
chunkSizeBytes: options2.chunkSizeBytes,
|
|
266207
|
-
rpc: options2.rpc,
|
|
266208
|
-
startedAtIso,
|
|
266209
|
-
finishedAtIso,
|
|
266210
|
-
heapLimitBytes: v8.getHeapStatistics().heap_size_limit,
|
|
266211
|
-
initialConcurrency: options2.initialConcurrency,
|
|
266212
|
-
maxConcurrency: options2.maxConcurrency
|
|
266213
|
-
},
|
|
266214
|
-
samples,
|
|
266215
|
-
waves,
|
|
266216
|
-
summary: {
|
|
266217
|
-
totalUploadTimeMs,
|
|
266218
|
-
totalUploadTimeSeconds: totalUploadTimeMs / 1000,
|
|
266219
|
-
elapsedMs: totalUploadTimeMs,
|
|
266220
|
-
throughputBytesPerSecond,
|
|
266221
|
-
peakHeapUsed,
|
|
266222
|
-
peakRss,
|
|
266223
|
-
peakArrayBuffers,
|
|
266224
|
-
peakExternal,
|
|
266225
|
-
retryCount: latestSchedulerState.retries,
|
|
266226
|
-
maxWindowReached,
|
|
266227
|
-
finalCid
|
|
265791
|
+
process.exit(0);
|
|
265792
|
+
} catch (error2) {
|
|
265793
|
+
const errorMessage = formatErrorMessage(error2);
|
|
265794
|
+
const jsonOutput = getJsonFlag(command);
|
|
265795
|
+
if (jsonOutput) {
|
|
265796
|
+
writeBulletinJsonError(errorMessage);
|
|
265797
|
+
} else {
|
|
265798
|
+
console.error(source_default.red(`
|
|
265799
|
+
✗ Error: ${errorMessage}
|
|
265800
|
+
`));
|
|
265801
|
+
process.exit(1);
|
|
266228
265802
|
}
|
|
266229
|
-
};
|
|
266230
|
-
const outputPath = overrideOutputPath ?? options2.outputPath ?? buildDefaultProfileOutputPath(options2.sourcePath, createProfileFingerprint(`${options2.sourcePath}:${options2.sourceSizeBytes}:${options2.chunkSizeBytes}:${startedAtIso}`));
|
|
266231
|
-
const resolvedOutputPath = path9.resolve(outputPath);
|
|
266232
|
-
await filesystem2.mkdir(path9.dirname(resolvedOutputPath), { recursive: true });
|
|
266233
|
-
await filesystem2.writeFile(resolvedOutputPath, JSON.stringify(report, null, 2), "utf8");
|
|
266234
|
-
return { report, outputPath: resolvedOutputPath };
|
|
266235
|
-
};
|
|
266236
|
-
return {
|
|
266237
|
-
onSchedulerState: (state3) => {
|
|
266238
|
-
latestSchedulerState = state3;
|
|
266239
|
-
captureSample();
|
|
266240
|
-
},
|
|
266241
|
-
onWave: (wave) => {
|
|
266242
|
-
waves.push(wave);
|
|
266243
|
-
captureSample();
|
|
266244
|
-
},
|
|
266245
|
-
finalize: summarizeAndWrite
|
|
266246
|
-
};
|
|
266247
|
-
}
|
|
266248
|
-
async function withCapturedConsole(callback) {
|
|
266249
|
-
const MAX_CAPTURED_ENTRIES = 400;
|
|
266250
|
-
const captured = [];
|
|
266251
|
-
const pushCaptured = (value3) => {
|
|
266252
|
-
captured.push(value3);
|
|
266253
|
-
if (captured.length > MAX_CAPTURED_ENTRIES) {
|
|
266254
|
-
captured.splice(0, captured.length - MAX_CAPTURED_ENTRIES);
|
|
266255
265803
|
}
|
|
266256
|
-
};
|
|
266257
|
-
const
|
|
266258
|
-
|
|
266259
|
-
};
|
|
266260
|
-
const captureWrite = (chunk) => {
|
|
266261
|
-
pushCaptured(String(chunk));
|
|
266262
|
-
return true;
|
|
266263
|
-
};
|
|
266264
|
-
const saved = {
|
|
266265
|
-
log: console.log,
|
|
266266
|
-
error: console.error,
|
|
266267
|
-
warn: console.warn,
|
|
266268
|
-
info: console.info,
|
|
266269
|
-
stdoutWrite: process.stdout.write.bind(process.stdout),
|
|
266270
|
-
stderrWrite: process.stderr.write.bind(process.stderr)
|
|
266271
|
-
};
|
|
266272
|
-
console.log = capture;
|
|
266273
|
-
console.error = capture;
|
|
266274
|
-
console.warn = capture;
|
|
266275
|
-
console.info = capture;
|
|
266276
|
-
process.stdout.write = captureWrite;
|
|
266277
|
-
process.stderr.write = captureWrite;
|
|
266278
|
-
try {
|
|
266279
|
-
return await callback();
|
|
266280
|
-
} catch (error2) {
|
|
266281
|
-
saved.error(`[captured output before failure]
|
|
266282
|
-
` + captured.join(`
|
|
266283
|
-
`));
|
|
266284
|
-
throw error2;
|
|
266285
|
-
} finally {
|
|
266286
|
-
console.log = saved.log;
|
|
266287
|
-
console.error = saved.error;
|
|
266288
|
-
console.warn = saved.warn;
|
|
266289
|
-
console.info = saved.info;
|
|
266290
|
-
process.stdout.write = saved.stdoutWrite;
|
|
266291
|
-
process.stderr.write = saved.stderrWrite;
|
|
266292
|
-
}
|
|
266293
|
-
}
|
|
266294
|
-
function maybeQuiet(jsonOutput, callback) {
|
|
266295
|
-
return jsonOutput ? withCapturedConsole(callback) : callback();
|
|
266296
|
-
}
|
|
266297
|
-
async function withBulletinHumanOutput(reporterMode, callback) {
|
|
266298
|
-
if (reporterMode === "quiet") {
|
|
266299
|
-
return withCapturedConsole(callback);
|
|
266300
|
-
}
|
|
266301
|
-
return withConsoleToStderr(callback);
|
|
266302
|
-
}
|
|
266303
|
-
async function resolveTargetAddress(positionalAddress, mergedOptions, reporterMode) {
|
|
266304
|
-
if (positionalAddress)
|
|
266305
|
-
return positionalAddress;
|
|
266306
|
-
const context = await withBulletinHumanOutput(reporterMode, () => prepareContext({ ...mergedOptions, useBulletin: true }));
|
|
266307
|
-
return context.substrateAddress;
|
|
266308
|
-
}
|
|
266309
|
-
function writeBulletinJson(payload) {
|
|
266310
|
-
process.stdout.write(`${JSON.stringify(payload)}
|
|
266311
|
-
`);
|
|
266312
|
-
}
|
|
266313
|
-
function writeBulletinJsonError(error2) {
|
|
266314
|
-
writeBulletinJson({ error: formatErrorMessage(error2) });
|
|
266315
|
-
process.exit(1);
|
|
266316
|
-
}
|
|
266317
|
-
function createPhaseHandler(reporter) {
|
|
266318
|
-
const tasks = new Map;
|
|
266319
|
-
return (event) => {
|
|
266320
|
-
const key = event.phase;
|
|
266321
|
-
const activeTask = tasks.get(key);
|
|
266322
|
-
if (event.state === "start") {
|
|
266323
|
-
activeTask?.stop();
|
|
266324
|
-
tasks.set(key, reporter.task(event.message));
|
|
266325
|
-
return;
|
|
266326
|
-
}
|
|
266327
|
-
if (event.state === "update") {
|
|
266328
|
-
if (activeTask) {
|
|
266329
|
-
activeTask.update(event.message);
|
|
266330
|
-
} else {
|
|
266331
|
-
tasks.set(key, reporter.task(event.message));
|
|
266332
|
-
}
|
|
266333
|
-
return;
|
|
266334
|
-
}
|
|
266335
|
-
if (event.state === "success") {
|
|
266336
|
-
if (activeTask) {
|
|
266337
|
-
activeTask.succeed(event.message);
|
|
266338
|
-
tasks.delete(key);
|
|
266339
|
-
} else {
|
|
266340
|
-
reporter.success(event.message);
|
|
266341
|
-
}
|
|
266342
|
-
return;
|
|
266343
|
-
}
|
|
266344
|
-
if (event.state === "warning") {
|
|
266345
|
-
if (activeTask) {
|
|
266346
|
-
activeTask.warn(event.message);
|
|
266347
|
-
tasks.delete(key);
|
|
266348
|
-
} else {
|
|
266349
|
-
reporter.warn(event.message);
|
|
266350
|
-
}
|
|
266351
|
-
return;
|
|
266352
|
-
}
|
|
266353
|
-
if (activeTask) {
|
|
266354
|
-
activeTask.fail(event.message);
|
|
266355
|
-
tasks.delete(key);
|
|
266356
|
-
return;
|
|
266357
|
-
}
|
|
266358
|
-
reporter.fail(event.message);
|
|
266359
|
-
};
|
|
266360
|
-
}
|
|
266361
|
-
function createRetryHandler(reporter) {
|
|
266362
|
-
return ({ label, retry, totalAttempts, delayMs, errorMessage }) => {
|
|
266363
|
-
reporter.warn(`${label} attempt ${retry + 1}/${totalAttempts} failed: ${errorMessage}`);
|
|
266364
|
-
reporter.detail(`retrying in ${(delayMs / 1000).toFixed(delayMs >= 1000 ? 1 : 0)}s`);
|
|
266365
|
-
};
|
|
266366
|
-
}
|
|
266367
|
-
function createChunkedUploadMonitor(reporter, phaseHandler, fileSize, chunkSizeBytes, totalChunks) {
|
|
266368
|
-
const heartbeatIntervalMs = 15000;
|
|
266369
|
-
let latestState = null;
|
|
266370
|
-
let heartbeatTimer;
|
|
266371
|
-
const startedAtMs = Date.now();
|
|
266372
|
-
const stopHeartbeat = () => {
|
|
266373
|
-
if (heartbeatTimer) {
|
|
266374
|
-
clearInterval(heartbeatTimer);
|
|
266375
|
-
heartbeatTimer = undefined;
|
|
266376
|
-
}
|
|
266377
|
-
};
|
|
266378
|
-
const emitHeartbeat = () => {
|
|
266379
|
-
if (!latestState || latestState.inFlightChunks === 0) {
|
|
266380
|
-
stopHeartbeat();
|
|
266381
|
-
return;
|
|
266382
|
-
}
|
|
266383
|
-
reporter.detail(`heartbeat | ${latestState.completedChunks}/${totalChunks} chunks | window=${latestState.window} | in-flight=${latestState.inFlightChunks} | bytes=${formatBytes(latestState.inFlightBytes)} | retries=${latestState.retries} | elapsed=${formatDuration((Date.now() - startedAtMs) / 1000)}`);
|
|
266384
|
-
};
|
|
266385
|
-
return {
|
|
266386
|
-
onSchedulerState(state3) {
|
|
266387
|
-
latestState = state3;
|
|
266388
|
-
if (reporter.mode !== "stream") {
|
|
266389
|
-
return;
|
|
266390
|
-
}
|
|
266391
|
-
if (state3.inFlightChunks > 0 && !heartbeatTimer) {
|
|
266392
|
-
heartbeatTimer = setInterval(emitHeartbeat, heartbeatIntervalMs);
|
|
266393
|
-
heartbeatTimer.unref?.();
|
|
266394
|
-
} else if (state3.inFlightChunks === 0) {
|
|
266395
|
-
stopHeartbeat();
|
|
266396
|
-
}
|
|
266397
|
-
},
|
|
266398
|
-
onWave(wave) {
|
|
266399
|
-
const completedChunks = latestState?.completedChunks ?? 0;
|
|
266400
|
-
const bytesUploaded = Math.min(fileSize, completedChunks * chunkSizeBytes);
|
|
266401
|
-
const throughputBytesPerSecond = wave.durationMs > 0 ? wave.succeeded * chunkSizeBytes * 1000 / wave.durationMs : 0;
|
|
266402
|
-
const message2 = `wave #${wave.wave} complete | ${completedChunks}/${totalChunks} chunks | ${formatBytes(bytesUploaded)}/${formatBytes(fileSize)} | ${(wave.durationMs / 1000).toFixed(1)}s | window=${wave.window} | retries=${wave.retries} | ${formatBytes(throughputBytesPerSecond)}/s`;
|
|
266403
|
-
if (reporter.mode === "interactive") {
|
|
266404
|
-
phaseHandler({ phase: "upload", state: "update", message: message2 });
|
|
266405
|
-
} else {
|
|
266406
|
-
reporter.line(message2);
|
|
266407
|
-
}
|
|
266408
|
-
},
|
|
266409
|
-
stop() {
|
|
266410
|
-
stopHeartbeat();
|
|
266411
|
-
}
|
|
266412
|
-
};
|
|
266413
|
-
}
|
|
266414
|
-
function attachBulletinCommands(root) {
|
|
266415
|
-
const bulletinCommand = addReporterOption(root.command("bulletin").description("Bulletin storage utilities")).option("--json", "Write machine-readable JSON to stdout", false);
|
|
266416
|
-
addAuthOptions(bulletinCommand);
|
|
266417
|
-
const authorizeCommand = addReporterOption(bulletinCommand.command("authorize [address]").description("Authorize an account for Bulletin TransactionStorage").option("--bulletin-rpc <wsUrl>", "Bulletin WebSocket RPC endpoint", DEFAULT_BULLETIN_RPC).option("--transactions <count>", "Number of transactions to authorize", String(DEFAULT_AUTHORIZATION_TRANSACTIONS)).option("--bytes <count>", "Number of bytes to authorize", String(DEFAULT_AUTHORIZATION_BYTES)).option("--force", "Force re-authorization even if account appears already authorized", false).option("--json", "Write machine-readable JSON to stdout", false));
|
|
266418
|
-
addAuthOptions(authorizeCommand).action(async (positionalAddress, options2, command) => {
|
|
265804
|
+
});
|
|
265805
|
+
const historyCommand = addReporterOption(bulletinCommand.command("history").alias("list").description("List all uploaded CIDs").option("--json", "Write machine-readable JSON to stdout", false));
|
|
265806
|
+
historyCommand.action(async (_options, command) => {
|
|
266419
265807
|
try {
|
|
266420
|
-
const mergedOptions = getMergedOptions2(command, options2);
|
|
266421
|
-
const jsonOutput = getJsonFlag(command);
|
|
266422
|
-
const reporterMode = resolveReporterMode(mergedOptions.reporter);
|
|
266423
|
-
const reporter = createCliReporter(mergedOptions.reporter);
|
|
266424
|
-
const onPhase = createPhaseHandler(reporter);
|
|
266425
|
-
const bulletinRpc = String(mergedOptions.bulletinRpc || DEFAULT_BULLETIN_RPC);
|
|
266426
|
-
const transactions = Number(mergedOptions.transactions || DEFAULT_AUTHORIZATION_TRANSACTIONS);
|
|
266427
|
-
const bytes = BigInt(mergedOptions.bytes || DEFAULT_AUTHORIZATION_BYTES);
|
|
266428
|
-
const force = Boolean(options2.force);
|
|
266429
|
-
const signerKeyUri = String(mergedOptions.keyUri || DEFAULT_SUDO_KEY_URI);
|
|
266430
|
-
const targetAddress = await resolveTargetAddress(positionalAddress, mergedOptions, reporterMode);
|
|
266431
|
-
const signerContext = await withBulletinHumanOutput(reporterMode, () => prepareContext({ keyUri: signerKeyUri, useBulletin: true }));
|
|
266432
|
-
if (!jsonOutput) {
|
|
266433
|
-
console.log(source_default.blue(`
|
|
266434
|
-
▶ Bulletin Authorize`));
|
|
266435
|
-
console.log(source_default.gray(" target: ") + source_default.cyan(targetAddress));
|
|
266436
|
-
console.log(source_default.gray(" rpc: ") + source_default.white(bulletinRpc));
|
|
266437
|
-
console.log(source_default.gray(" transactions: ") + source_default.white(transactions.toLocaleString()));
|
|
266438
|
-
console.log(source_default.gray(" bytes: ") + source_default.white(formatBytes(bytes)));
|
|
266439
|
-
console.log(source_default.gray(" signer: ") + source_default.yellow(signerKeyUri));
|
|
266440
|
-
}
|
|
266441
|
-
await withBulletinHumanOutput(reporterMode, () => authorizeAccount({
|
|
266442
|
-
rpc: bulletinRpc,
|
|
266443
|
-
signer: signerContext.signer,
|
|
266444
|
-
targetAddress,
|
|
266445
|
-
transactions,
|
|
266446
|
-
bytes,
|
|
266447
|
-
force,
|
|
266448
|
-
onPhase
|
|
266449
|
-
}));
|
|
266450
|
-
if (jsonOutput) {
|
|
266451
|
-
const authStatus = await checkAuthorization(bulletinRpc, targetAddress);
|
|
266452
|
-
const expiresAt = expirationToISOString(authStatus.currentBlock, authStatus.expiration);
|
|
266453
|
-
writeBulletinJson({
|
|
266454
|
-
ok: true,
|
|
266455
|
-
target: targetAddress,
|
|
266456
|
-
rpc: bulletinRpc,
|
|
266457
|
-
transactions,
|
|
266458
|
-
bytes: bytes.toString(),
|
|
266459
|
-
expiresAt
|
|
266460
|
-
});
|
|
266461
|
-
} else {
|
|
266462
|
-
console.log(source_default.green(`
|
|
266463
|
-
✓ Authorization Complete`));
|
|
266464
|
-
console.log(source_default.gray(` The account can now upload to Bulletin.
|
|
266465
|
-
`));
|
|
266466
|
-
}
|
|
266467
|
-
process.exit(0);
|
|
266468
|
-
} catch (error2) {
|
|
266469
|
-
const errorMessage = formatErrorMessage(error2);
|
|
266470
265808
|
const jsonOutput = getJsonFlag(command);
|
|
265809
|
+
const history = await readHistory();
|
|
266471
265810
|
if (jsonOutput) {
|
|
266472
|
-
|
|
265811
|
+
writeBulletinJson(history);
|
|
265812
|
+
process.exit(0);
|
|
266473
265813
|
}
|
|
266474
|
-
if (
|
|
265814
|
+
if (history.length === 0) {
|
|
266475
265815
|
console.log(source_default.yellow(`
|
|
266476
|
-
|
|
265816
|
+
No uploads in history.
|
|
265817
|
+
`));
|
|
265818
|
+
console.log(source_default.gray(` Upload files with: dotns bulletin upload <path>
|
|
266477
265819
|
`));
|
|
266478
265820
|
process.exit(0);
|
|
266479
265821
|
}
|
|
266480
|
-
|
|
266481
|
-
|
|
266482
|
-
✗ Authorization failed — insufficient privileges`));
|
|
266483
|
-
console.error(source_default.yellow(" The signer does not have Authorizer privileges on this chain."));
|
|
266484
|
-
console.error(source_default.gray(` Override with --key-uri if needed.
|
|
265822
|
+
console.log(source_default.blue(`
|
|
265823
|
+
▶ Upload History
|
|
266485
265824
|
`));
|
|
266486
|
-
|
|
266487
|
-
}
|
|
266488
|
-
if (errorMessage.includes("not applied")) {
|
|
266489
|
-
console.error(source_default.red(`
|
|
266490
|
-
✗ ${errorMessage}`));
|
|
266491
|
-
console.error(source_default.gray(` Override with --key-uri if needed.
|
|
265825
|
+
console.log(source_default.gray(` ${history.length} upload(s) found
|
|
266492
265826
|
`));
|
|
266493
|
-
|
|
265827
|
+
history.forEach((record2, index) => {
|
|
265828
|
+
const num = (index + 1).toString().padStart(2, " ");
|
|
265829
|
+
console.log(source_default.yellow(` ${num}.`) + source_default.white(` ${formatRecordTimestamp(record2)}`));
|
|
265830
|
+
console.log(source_default.gray(" cid: ") + source_default.cyan(record2.cid));
|
|
265831
|
+
console.log(source_default.gray(" path: ") + source_default.white(record2.path));
|
|
265832
|
+
console.log(source_default.gray(" type: ") + source_default.white(record2.type));
|
|
265833
|
+
if (record2.size > 0) {
|
|
265834
|
+
console.log(source_default.gray(" size: ") + source_default.white(formatBytes(record2.size)));
|
|
265835
|
+
}
|
|
265836
|
+
console.log(source_default.gray(" preview: ") + source_default.blue(getPreviewUrl(record2)));
|
|
265837
|
+
console.log();
|
|
265838
|
+
});
|
|
265839
|
+
process.exit(0);
|
|
265840
|
+
} catch (error2) {
|
|
265841
|
+
const jsonOutput = getJsonFlag(command);
|
|
265842
|
+
if (jsonOutput) {
|
|
265843
|
+
writeBulletinJsonError(error2);
|
|
266494
265844
|
}
|
|
266495
265845
|
console.error(source_default.red(`
|
|
266496
|
-
✗ Error: ${
|
|
265846
|
+
✗ Error: ${formatErrorMessage(error2)}
|
|
266497
265847
|
`));
|
|
266498
265848
|
process.exit(1);
|
|
266499
265849
|
}
|
|
266500
265850
|
});
|
|
266501
|
-
|
|
266502
|
-
addAuthOptions(uploadCommand).action(async (inputPath, options2, command) => {
|
|
265851
|
+
bulletinCommand.command("history:remove <cid>").description("Remove an upload from history by CID").action(async (cid) => {
|
|
266503
265852
|
try {
|
|
266504
|
-
const
|
|
266505
|
-
|
|
266506
|
-
|
|
266507
|
-
|
|
266508
|
-
|
|
266509
|
-
|
|
266510
|
-
|
|
266511
|
-
|
|
265853
|
+
const removed = await removeUploadRecord(cid);
|
|
265854
|
+
if (removed) {
|
|
265855
|
+
console.log(source_default.green(`
|
|
265856
|
+
✓ Removed ${cid} from history
|
|
265857
|
+
`));
|
|
265858
|
+
} else {
|
|
265859
|
+
console.log(source_default.yellow(`
|
|
265860
|
+
⚠ CID not found in history: ${cid}
|
|
265861
|
+
`));
|
|
266512
265862
|
}
|
|
266513
|
-
|
|
266514
|
-
|
|
266515
|
-
|
|
266516
|
-
|
|
266517
|
-
|
|
266518
|
-
|
|
266519
|
-
|
|
266520
|
-
|
|
266521
|
-
|
|
266522
|
-
|
|
266523
|
-
const
|
|
266524
|
-
|
|
266525
|
-
|
|
266526
|
-
|
|
266527
|
-
|
|
266528
|
-
|
|
266529
|
-
|
|
266530
|
-
|
|
266531
|
-
|
|
266532
|
-
|
|
266533
|
-
|
|
266534
|
-
|
|
266535
|
-
|
|
266536
|
-
|
|
266537
|
-
|
|
266538
|
-
|
|
266539
|
-
|
|
265863
|
+
process.exit(0);
|
|
265864
|
+
} catch (error2) {
|
|
265865
|
+
console.error(source_default.red(`
|
|
265866
|
+
✗ Error: ${formatErrorMessage(error2)}
|
|
265867
|
+
`));
|
|
265868
|
+
process.exit(1);
|
|
265869
|
+
}
|
|
265870
|
+
});
|
|
265871
|
+
addReporterOption(bulletinCommand.command("history:clear").description("Clear all upload history")).action(async () => {
|
|
265872
|
+
try {
|
|
265873
|
+
const count2 = await clearHistory();
|
|
265874
|
+
const historyPath = getHistoryPath();
|
|
265875
|
+
console.log(source_default.green(`
|
|
265876
|
+
✓ Cleared ${count2} upload(s) from history`));
|
|
265877
|
+
console.log(source_default.gray(` ${historyPath}
|
|
265878
|
+
`));
|
|
265879
|
+
process.exit(0);
|
|
265880
|
+
} catch (error2) {
|
|
265881
|
+
console.error(source_default.red(`
|
|
265882
|
+
✗ Error: ${formatErrorMessage(error2)}
|
|
265883
|
+
`));
|
|
265884
|
+
process.exit(1);
|
|
265885
|
+
}
|
|
265886
|
+
});
|
|
265887
|
+
addReporterOption(bulletinCommand.command("verify <cid>").description("Verify a CID is resolvable via IPFS gateways").option("--json", "Write machine-readable JSON to stdout", false)).action(async (cid, options2, command) => {
|
|
265888
|
+
const mergedOptions = getMergedOptions(command, options2);
|
|
265889
|
+
const jsonOutput = getJsonFlag(command) || Boolean(options2.json);
|
|
265890
|
+
const reporter = createCliReporter(mergedOptions.reporter);
|
|
265891
|
+
const p2pTask = reporter.task("Connecting to Bulletin P2P");
|
|
265892
|
+
try {
|
|
265893
|
+
if (!jsonOutput) {
|
|
265894
|
+
console.log(source_default.blue(`
|
|
265895
|
+
▶ Verifying CID`));
|
|
265896
|
+
console.log(source_default.gray(" cid: ") + source_default.cyan(cid));
|
|
266540
265897
|
}
|
|
266541
|
-
const
|
|
266542
|
-
|
|
266543
|
-
|
|
266544
|
-
|
|
266545
|
-
|
|
266546
|
-
|
|
266547
|
-
|
|
266548
|
-
|
|
266549
|
-
|
|
266550
|
-
maxConcurrency: shouldUseChunkedUpload ? concurrency : 1,
|
|
266551
|
-
outputPath: profileOutputOverride,
|
|
266552
|
-
jsonOutput
|
|
266553
|
-
}) : undefined;
|
|
266554
|
-
const totalChunks = shouldUseChunkedUpload ? Math.ceil(effectiveFileSize / chunkSizeBytes) : undefined;
|
|
266555
|
-
const chunkedMonitor = shouldUseChunkedUpload && totalChunks ? createChunkedUploadMonitor(reporter, onPhase, effectiveFileSize, chunkSizeBytes, totalChunks) : null;
|
|
266556
|
-
const performUpload = async () => {
|
|
266557
|
-
if (isDirectory) {
|
|
266558
|
-
const result2 = await storeDirectory(bulletinRpc, context.signer, resolvedPath, {
|
|
266559
|
-
concurrency,
|
|
266560
|
-
accountAddress: context.substrateAddress,
|
|
266561
|
-
maxRetries,
|
|
266562
|
-
onPhase,
|
|
266563
|
-
onRetry,
|
|
266564
|
-
waitForFinalization: false
|
|
266565
|
-
});
|
|
266566
|
-
return { cid: result2.cid, size: 0 };
|
|
266567
|
-
}
|
|
266568
|
-
if (shouldUseChunkedUpload) {
|
|
266569
|
-
const result2 = await uploadChunkedBlocks(bulletinRpc, context.signer, resolvedPath, chunkSizeBytes, effectiveFileSize, context.substrateAddress, {
|
|
266570
|
-
completedBlocks: resumedBlocks,
|
|
266571
|
-
concurrency,
|
|
266572
|
-
maxRetries,
|
|
266573
|
-
onPhase,
|
|
266574
|
-
onRetry,
|
|
266575
|
-
onSchedulerState: (state3) => {
|
|
266576
|
-
profiler?.onSchedulerState(state3);
|
|
266577
|
-
chunkedMonitor?.onSchedulerState(state3);
|
|
266578
|
-
},
|
|
266579
|
-
onWave: (wave) => {
|
|
266580
|
-
profiler?.onWave(wave);
|
|
266581
|
-
chunkedMonitor?.onWave(wave);
|
|
266582
|
-
}
|
|
265898
|
+
const p2pResult = await verifyCidViaP2P(cid);
|
|
265899
|
+
if (p2pResult.resolvable) {
|
|
265900
|
+
p2pTask.succeed("CID verified via P2P (bitswap)");
|
|
265901
|
+
if (jsonOutput) {
|
|
265902
|
+
writeBulletinJson({
|
|
265903
|
+
cid,
|
|
265904
|
+
resolvable: true,
|
|
265905
|
+
method: "p2p",
|
|
265906
|
+
gateways: [{ gateway: "p2p/bitswap", resolvable: true }]
|
|
266583
265907
|
});
|
|
266584
|
-
return { cid: result2, size: effectiveFileSize };
|
|
266585
|
-
}
|
|
266586
|
-
const result = await uploadSingleBlock(bulletinRpc, context.signer, bytes, {
|
|
266587
|
-
maxRetries,
|
|
266588
|
-
onPhase,
|
|
266589
|
-
onRetry
|
|
266590
|
-
});
|
|
266591
|
-
return { cid: result, size: bytes.length };
|
|
266592
|
-
};
|
|
266593
|
-
let cid;
|
|
266594
|
-
let uploadSize;
|
|
266595
|
-
let profileReportPath;
|
|
266596
|
-
let profileReport;
|
|
266597
|
-
const uploadStartedAtMs = Date.now();
|
|
266598
|
-
const uploadStartedAtIso = new Date(uploadStartedAtMs).toISOString();
|
|
266599
|
-
const pathBasename = resolvedPath.split("/").pop() ?? resolvedPath;
|
|
266600
|
-
if (authInfo?.expiration && authInfo.currentBlock) {
|
|
266601
|
-
reporter.detail(`auth: valid (expires ${formatExpirationDisplay(authInfo.currentBlock, authInfo.expiration)})`);
|
|
266602
|
-
}
|
|
266603
|
-
if (!jsonOutput) {
|
|
266604
|
-
if (isDirectory) {
|
|
266605
|
-
console.log(source_default.blue(`
|
|
266606
|
-
▶ Uploading directory: ${pathBasename}`));
|
|
266607
|
-
console.log(source_default.gray(" path: ") + source_default.white(resolvedPath));
|
|
266608
|
-
console.log(source_default.gray(" rpc: ") + source_default.white(bulletinRpc));
|
|
266609
|
-
console.log(source_default.gray(" concurrency: ") + source_default.white(`${concurrency}x parallel waves`));
|
|
266610
|
-
} else if (shouldUseChunkedUpload) {
|
|
266611
|
-
console.log(source_default.blue(`
|
|
266612
|
-
▶ Uploading file: ${pathBasename} (${formatBytes(effectiveFileSize)})`));
|
|
266613
|
-
console.log(source_default.gray(" path: ") + source_default.white(resolvedPath));
|
|
266614
|
-
console.log(source_default.gray(" rpc: ") + source_default.white(bulletinRpc));
|
|
266615
|
-
console.log(source_default.gray(" mode: ") + source_default.white(`chunked (${totalChunks} × ${formatBytes(chunkSizeBytes)}, adaptive window 1..${concurrency})`));
|
|
266616
265908
|
} else {
|
|
266617
|
-
console.log(source_default.
|
|
266618
|
-
|
|
266619
|
-
console.log(source_default.gray(" path: ") + source_default.white(resolvedPath));
|
|
266620
|
-
console.log(source_default.gray(" rpc: ") + source_default.white(bulletinRpc));
|
|
266621
|
-
console.log(source_default.gray(" mode: ") + source_default.white("single block"));
|
|
265909
|
+
console.log(source_default.gray(" ✓ ") + source_default.white("p2p/bitswap"));
|
|
265910
|
+
console.log();
|
|
266622
265911
|
}
|
|
265912
|
+
cleanupHeliaAndExit(0);
|
|
266623
265913
|
}
|
|
266624
|
-
|
|
266625
|
-
|
|
266626
|
-
|
|
266627
|
-
|
|
266628
|
-
|
|
266629
|
-
|
|
266630
|
-
|
|
266631
|
-
|
|
266632
|
-
const uploadFinishedAtIso = new Date(uploadFinishedAtMs).toISOString();
|
|
266633
|
-
const totalUploadTimeMs = Math.max(1, uploadFinishedAtMs - uploadStartedAtMs);
|
|
266634
|
-
const totalUploadTimeSeconds = totalUploadTimeMs / 1000;
|
|
266635
|
-
if (profiler) {
|
|
266636
|
-
const finalizedProfile = await profiler.finalize(cid, profileOutputOverride);
|
|
266637
|
-
profileReport = finalizedProfile.report;
|
|
266638
|
-
profileReportPath = finalizedProfile.outputPath;
|
|
266639
|
-
}
|
|
266640
|
-
onPhase({
|
|
266641
|
-
phase: "verify",
|
|
266642
|
-
state: "start",
|
|
266643
|
-
message: "Verifying content on Bulletin P2P..."
|
|
266644
|
-
});
|
|
266645
|
-
let verified = false;
|
|
266646
|
-
try {
|
|
266647
|
-
const p2pResult = await verifyCidViaP2P(cid);
|
|
266648
|
-
if (p2pResult.resolvable) {
|
|
266649
|
-
onPhase({ phase: "verify", state: "success", message: "Content verified via P2P" });
|
|
266650
|
-
verified = true;
|
|
266651
|
-
}
|
|
266652
|
-
} catch {}
|
|
266653
|
-
if (!verified) {
|
|
266654
|
-
onPhase({
|
|
266655
|
-
phase: "verify",
|
|
266656
|
-
state: "update",
|
|
266657
|
-
message: "P2P unavailable, checking IPFS gateways..."
|
|
266658
|
-
});
|
|
266659
|
-
const gatewayResults = await verifyCidWithMultipleGateways(cid);
|
|
266660
|
-
const resolvable = Array.from(gatewayResults.values()).some((r2) => r2.resolvable);
|
|
266661
|
-
if (resolvable) {
|
|
266662
|
-
onPhase({
|
|
266663
|
-
phase: "verify",
|
|
266664
|
-
state: "success",
|
|
266665
|
-
message: "Content verified via IPFS gateway"
|
|
266666
|
-
});
|
|
265914
|
+
p2pTask.warn("P2P verification failed, falling back to gateways");
|
|
265915
|
+
const gatewayTask = reporter.task("Checking IPFS gateways");
|
|
265916
|
+
const results = await verifyCidWithMultipleGateways(cid);
|
|
265917
|
+
const resolvableGateways = [];
|
|
265918
|
+
const failedGateways = [];
|
|
265919
|
+
for (const [gateway, result] of results) {
|
|
265920
|
+
if (result.resolvable) {
|
|
265921
|
+
resolvableGateways.push(gateway);
|
|
266667
265922
|
} else {
|
|
266668
|
-
|
|
266669
|
-
phase: "verify",
|
|
266670
|
-
state: "warning",
|
|
266671
|
-
message: "Content not yet resolvable — it may still be propagating"
|
|
266672
|
-
});
|
|
265923
|
+
failedGateways.push(gateway);
|
|
266673
265924
|
}
|
|
266674
265925
|
}
|
|
266675
|
-
const contenthash = generateContenthash(cid);
|
|
266676
|
-
const previewUrl = getPreviewUrl({
|
|
266677
|
-
cid,
|
|
266678
|
-
path: resolvedPath,
|
|
266679
|
-
type: isDirectory ? "directory" : "file",
|
|
266680
|
-
size: uploadSize,
|
|
266681
|
-
timestamp: ""
|
|
266682
|
-
});
|
|
266683
265926
|
if (jsonOutput) {
|
|
266684
|
-
const
|
|
265927
|
+
const entries = Array.from(results.entries()).map(([gateway, result]) => ({
|
|
265928
|
+
gateway,
|
|
265929
|
+
resolvable: result.resolvable,
|
|
265930
|
+
statusCode: result.statusCode,
|
|
265931
|
+
errorMessage: result.errorMessage
|
|
265932
|
+
}));
|
|
266685
265933
|
writeBulletinJson({
|
|
266686
265934
|
cid,
|
|
266687
|
-
|
|
266688
|
-
|
|
266689
|
-
|
|
266690
|
-
type: isDirectory ? "directory" : "file",
|
|
266691
|
-
size: uploadSize,
|
|
266692
|
-
authorizationExpiresAt: authExpiresAt,
|
|
266693
|
-
uploadStartedAtIso,
|
|
266694
|
-
uploadFinishedAtIso,
|
|
266695
|
-
totalUploadTimeMs,
|
|
266696
|
-
totalUploadTimeSeconds
|
|
265935
|
+
resolvable: resolvableGateways.length > 0,
|
|
265936
|
+
method: resolvableGateways.length > 0 ? "gateway" : "none",
|
|
265937
|
+
gateways: entries
|
|
266697
265938
|
});
|
|
265939
|
+
cleanupHeliaAndExit(resolvableGateways.length > 0 ? 0 : 1);
|
|
265940
|
+
}
|
|
265941
|
+
if (resolvableGateways.length > 0) {
|
|
265942
|
+
gatewayTask.succeed(`CID resolvable on ${resolvableGateways.length} gateway(s)`);
|
|
265943
|
+
for (const gw of resolvableGateways) {
|
|
265944
|
+
console.log(source_default.gray(" ✓ ") + source_default.white(gw));
|
|
265945
|
+
}
|
|
266698
265946
|
} else {
|
|
266699
|
-
|
|
266700
|
-
|
|
266701
|
-
|
|
266702
|
-
|
|
266703
|
-
|
|
266704
|
-
console.log(source_default.gray(" contenthash: ") + source_default.white(`0x${contenthash}`));
|
|
266705
|
-
}
|
|
266706
|
-
if (profileReportPath && profileReport) {
|
|
266707
|
-
console.log(source_default.gray(" profile: ") + source_default.white(profileReportPath));
|
|
266708
|
-
console.log(source_default.gray(" throughput: ") + source_default.white(`${formatBytes(profileReport.summary.throughputBytesPerSecond)}/s`));
|
|
266709
|
-
console.log(source_default.gray(" peak heap: ") + source_default.white(formatBytes(profileReport.summary.peakHeapUsed)));
|
|
265947
|
+
gatewayTask.fail("CID not resolvable on any gateway");
|
|
265948
|
+
}
|
|
265949
|
+
if (failedGateways.length > 0 && resolvableGateways.length > 0) {
|
|
265950
|
+
for (const gw of failedGateways) {
|
|
265951
|
+
console.log(source_default.gray(" ✗ ") + source_default.dim(gw));
|
|
266710
265952
|
}
|
|
266711
|
-
|
|
266712
|
-
|
|
265953
|
+
}
|
|
265954
|
+
console.log();
|
|
265955
|
+
cleanupHeliaAndExit(resolvableGateways.length > 0 ? 0 : 1);
|
|
265956
|
+
} catch (error2) {
|
|
265957
|
+
p2pTask.fail("Verification failed");
|
|
265958
|
+
const errorMessage = formatErrorMessage(error2);
|
|
265959
|
+
if (jsonOutput) {
|
|
265960
|
+
writeBulletinJsonError(errorMessage);
|
|
265961
|
+
} else {
|
|
265962
|
+
console.error(source_default.red(`
|
|
265963
|
+
✗ Error: ${errorMessage}
|
|
266713
265964
|
`));
|
|
265965
|
+
cleanupHeliaAndExit(1);
|
|
266714
265966
|
}
|
|
266715
|
-
|
|
266716
|
-
|
|
266717
|
-
|
|
266718
|
-
|
|
266719
|
-
|
|
266720
|
-
|
|
266721
|
-
|
|
266722
|
-
|
|
266723
|
-
|
|
266724
|
-
|
|
266725
|
-
|
|
266726
|
-
|
|
266727
|
-
|
|
266728
|
-
|
|
266729
|
-
|
|
266730
|
-
|
|
266731
|
-
|
|
266732
|
-
|
|
266733
|
-
|
|
266734
|
-
|
|
266735
|
-
|
|
266736
|
-
|
|
266737
|
-
|
|
266738
|
-
|
|
266739
|
-
|
|
266740
|
-
|
|
266741
|
-
|
|
266742
|
-
|
|
266743
|
-
|
|
266744
|
-
|
|
266745
|
-
|
|
266746
|
-
|
|
266747
|
-
|
|
266748
|
-
|
|
266749
|
-
|
|
266750
|
-
|
|
266751
|
-
|
|
266752
|
-
|
|
266753
|
-
|
|
266754
|
-
|
|
266755
|
-
|
|
266756
|
-
|
|
265967
|
+
}
|
|
265968
|
+
});
|
|
265969
|
+
}
|
|
265970
|
+
|
|
265971
|
+
// src/cli/commands/content.ts
|
|
265972
|
+
init_source();
|
|
265973
|
+
|
|
265974
|
+
// src/commands/contentHash.ts
|
|
265975
|
+
init_source();
|
|
265976
|
+
init__esm();
|
|
265977
|
+
init_constants();
|
|
265978
|
+
init_contractInteractions();
|
|
265979
|
+
|
|
265980
|
+
// src/commands/resolverAuth.ts
|
|
265981
|
+
init__esm();
|
|
265982
|
+
init_constants();
|
|
265983
|
+
init_contractInteractions();
|
|
265984
|
+
async function getResolverNodeInfo(clientWrapper, originSubstrateAddress, namehashNode) {
|
|
265985
|
+
const exists2 = await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRY, DOTNS_REGISTRY_ABI, "recordExists", [namehashNode]);
|
|
265986
|
+
const owner = await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRY, DOTNS_REGISTRY_ABI, "owner", [namehashNode]);
|
|
265987
|
+
const caller = await clientWrapper.getEvmAddress(originSubstrateAddress);
|
|
265988
|
+
return { exists: exists2 && owner !== zeroAddress, owner, caller };
|
|
265989
|
+
}
|
|
265990
|
+
async function requireResolverAuthorization(clientWrapper, originSubstrateAddress, owner, caller) {
|
|
265991
|
+
const isOwner = checksumAddress(owner) === checksumAddress(caller);
|
|
265992
|
+
const isApproved = await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_CONTENT_RESOLVER, DOTNS_CONTENT_RESOLVER_ABI, "isApprovedForAll", [owner, caller]);
|
|
265993
|
+
if (!isOwner && !isApproved) {
|
|
265994
|
+
throw new Error(`You do not own this domain. Owner is ${owner}, but you are ${caller}`);
|
|
265995
|
+
}
|
|
265996
|
+
}
|
|
265997
|
+
|
|
265998
|
+
// src/commands/contentHash.ts
|
|
265999
|
+
function decodeContenthashToCid(contenthash) {
|
|
266000
|
+
if (contenthash === "0x" || contenthash === "0x0" || contenthash.length < 6) {
|
|
266001
|
+
return "No CID set";
|
|
266002
|
+
}
|
|
266003
|
+
const cid = decodeIpfsContenthash(contenthash);
|
|
266004
|
+
return cid ?? `Unable to decode: ${contenthash}`;
|
|
266005
|
+
}
|
|
266006
|
+
function encodeCidToContenthash(cidString) {
|
|
266007
|
+
const encoded = encodeIpfsContenthash(cidString);
|
|
266008
|
+
return `0x${encoded}`;
|
|
266009
|
+
}
|
|
266010
|
+
async function viewDomainContentHash(clientWrapper, originSubstrateAddress, label, spinner) {
|
|
266011
|
+
const namehashNode = namehash(`${label}.dot`);
|
|
266012
|
+
spinner.start("Querying registry");
|
|
266013
|
+
const recordExists = await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRY, DOTNS_REGISTRY_ABI, "recordExists", [namehashNode]);
|
|
266014
|
+
const ownerAddress = await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRY, DOTNS_REGISTRY_ABI, "owner", [namehashNode]);
|
|
266015
|
+
spinner.succeed("Registry read");
|
|
266016
|
+
console.log(source_default.gray(" registry: ") + source_default.white(CONTRACTS.DOTNS_REGISTRY));
|
|
266017
|
+
console.log(source_default.gray(" domain: ") + source_default.cyan(`${label}.dot`));
|
|
266018
|
+
console.log(source_default.gray(" node: ") + source_default.white(namehashNode));
|
|
266019
|
+
console.log(source_default.gray(" exists: ") + source_default.white(String(recordExists)));
|
|
266020
|
+
console.log(source_default.gray(" owner: ") + source_default.white(ownerAddress));
|
|
266021
|
+
console.log();
|
|
266022
|
+
if (!recordExists || ownerAddress === zeroAddress) {
|
|
266023
|
+
console.log(source_default.yellow(" status: Domain not registered"));
|
|
266024
|
+
return { domain: `${label}.dot`, contenthash: null, cid: null };
|
|
266025
|
+
}
|
|
266026
|
+
const contentHashBytes = await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_CONTENT_RESOLVER, DOTNS_CONTENT_RESOLVER_ABI, "contenthash", [namehashNode]);
|
|
266027
|
+
const decodedCid = decodeContenthashToCid(contentHashBytes);
|
|
266028
|
+
console.log(source_default.gray(" resolver: ") + source_default.white(CONTRACTS.DOTNS_CONTENT_RESOLVER));
|
|
266029
|
+
console.log(source_default.gray(" contenthash: ") + source_default.white(contentHashBytes));
|
|
266030
|
+
console.log(source_default.gray(" cid: ") + source_default.cyan(decodedCid));
|
|
266031
|
+
const hasContent = decodedCid !== "No CID set";
|
|
266032
|
+
const cidResolved = hasContent && !decodedCid.startsWith("Unable to decode:") ? decodedCid : null;
|
|
266033
|
+
return {
|
|
266034
|
+
domain: `${label}.dot`,
|
|
266035
|
+
contenthash: hasContent ? contentHashBytes : null,
|
|
266036
|
+
cid: cidResolved
|
|
266037
|
+
};
|
|
266038
|
+
}
|
|
266039
|
+
async function setDomainContentHash(clientWrapper, originSubstrateAddress, signer, label, contentId, spinner) {
|
|
266040
|
+
const namehashNode = namehash(`${label}.dot`);
|
|
266041
|
+
console.log(source_default.gray(" domain: ") + source_default.cyan(`${label}.dot`));
|
|
266042
|
+
console.log(source_default.gray(" node: ") + source_default.white(namehashNode));
|
|
266043
|
+
console.log();
|
|
266044
|
+
const { exists: exists2, owner, caller } = await getResolverNodeInfo(clientWrapper, originSubstrateAddress, namehashNode);
|
|
266045
|
+
console.log(source_default.gray(" exists: ") + source_default.white(String(exists2)));
|
|
266046
|
+
console.log(source_default.gray(" owner: ") + source_default.white(owner));
|
|
266047
|
+
console.log(source_default.gray(" caller: ") + source_default.white(caller));
|
|
266048
|
+
console.log();
|
|
266049
|
+
if (!exists2) {
|
|
266050
|
+
throw new Error(`Domain ${label}.dot is not registered`);
|
|
266051
|
+
}
|
|
266052
|
+
await requireResolverAuthorization(clientWrapper, originSubstrateAddress, owner, caller);
|
|
266053
|
+
console.log(source_default.gray(" status: ") + source_default.green("Ownership verified"));
|
|
266054
|
+
console.log();
|
|
266055
|
+
try {
|
|
266056
|
+
const currentContentHash = await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_CONTENT_RESOLVER, DOTNS_CONTENT_RESOLVER_ABI, "contenthash", [namehashNode]);
|
|
266057
|
+
const currentCid = decodeContenthashToCid(currentContentHash);
|
|
266058
|
+
console.log(source_default.gray(" current: ") + source_default.cyan(currentCid));
|
|
266059
|
+
} catch {
|
|
266060
|
+
console.log(source_default.gray(" current: ") + source_default.yellow("Not set or error reading"));
|
|
266061
|
+
}
|
|
266062
|
+
console.log();
|
|
266063
|
+
const contentBytes = encodeCidToContenthash(contentId);
|
|
266064
|
+
console.log(source_default.gray(" resolver: ") + source_default.white(CONTRACTS.DOTNS_CONTENT_RESOLVER));
|
|
266065
|
+
console.log(source_default.gray(" node: ") + source_default.white(namehashNode));
|
|
266066
|
+
console.log(source_default.gray(" cid: ") + source_default.cyan(contentId));
|
|
266067
|
+
console.log(source_default.gray(" bytes: ") + source_default.white(contentBytes));
|
|
266068
|
+
spinner.start("Submitting setContenthash");
|
|
266069
|
+
const transactionHash = await submitContractTransaction(clientWrapper, CONTRACTS.DOTNS_CONTENT_RESOLVER, 0n, DOTNS_CONTENT_RESOLVER_ABI, "setContenthash", [namehashNode, contentBytes], originSubstrateAddress, signer, spinner, "setContenthash");
|
|
266070
|
+
console.log(source_default.gray(" tx: ") + source_default.blue(transactionHash));
|
|
266071
|
+
const updatedContentHash = await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_CONTENT_RESOLVER, DOTNS_CONTENT_RESOLVER_ABI, "contenthash", [namehashNode]);
|
|
266072
|
+
const updatedCid = decodeContenthashToCid(updatedContentHash);
|
|
266073
|
+
console.log();
|
|
266074
|
+
console.log(source_default.gray(" new: ") + source_default.cyan(updatedCid));
|
|
266075
|
+
return {
|
|
266076
|
+
ok: true,
|
|
266077
|
+
domain: `${label}.dot`,
|
|
266078
|
+
cid: contentId,
|
|
266079
|
+
contenthash: contentBytes,
|
|
266080
|
+
txHash: transactionHash
|
|
266081
|
+
};
|
|
266082
|
+
}
|
|
266083
|
+
|
|
266084
|
+
// src/cli/commands/lookup.ts
|
|
266085
|
+
init_source();
|
|
266086
|
+
init_esm10();
|
|
266087
|
+
init_ws_provider();
|
|
266088
|
+
init_dist();
|
|
266089
|
+
init_polkadotClient();
|
|
266090
|
+
|
|
266091
|
+
// src/commands/lookup.ts
|
|
266092
|
+
init_source();
|
|
266093
|
+
init_ora();
|
|
266094
|
+
init__esm();
|
|
266095
|
+
init_constants();
|
|
266096
|
+
|
|
266097
|
+
// src/utils/validation.ts
|
|
266098
|
+
init__esm();
|
|
266099
|
+
function countTrailingDigits(label) {
|
|
266100
|
+
let count2 = 0;
|
|
266101
|
+
for (let characterIndex = label.length - 1;characterIndex >= 0; characterIndex--) {
|
|
266102
|
+
const asciiCode = label.charCodeAt(characterIndex);
|
|
266103
|
+
if (asciiCode >= 48 && asciiCode <= 57) {
|
|
266104
|
+
count2++;
|
|
266105
|
+
} else {
|
|
266106
|
+
break;
|
|
266107
|
+
}
|
|
266108
|
+
}
|
|
266109
|
+
return count2;
|
|
266110
|
+
}
|
|
266111
|
+
function stripTrailingDigits(label) {
|
|
266112
|
+
return label.replace(/\d+$/, "");
|
|
266113
|
+
}
|
|
266114
|
+
function validateDomainLabel(label) {
|
|
266115
|
+
if (!/^[a-z0-9-]{3,}$/.test(label)) {
|
|
266116
|
+
throw new Error("Invalid domain label: must contain only lowercase letters, digits, and hyphens, with minimum length of 3 characters");
|
|
266117
|
+
}
|
|
266118
|
+
if (label.startsWith("-") || label.endsWith("-")) {
|
|
266119
|
+
throw new Error("Invalid domain label: cannot start or end with hyphen");
|
|
266120
|
+
}
|
|
266121
|
+
const trailingDigitCount = countTrailingDigits(label);
|
|
266122
|
+
if (trailingDigitCount > 2) {
|
|
266123
|
+
throw new Error(`Invalid domain label: maximum 2 trailing digits allowed, found ${trailingDigitCount}`);
|
|
266124
|
+
}
|
|
266125
|
+
}
|
|
266126
|
+
function validateGovernanceLabel(label) {
|
|
266127
|
+
validateDomainLabel(label);
|
|
266128
|
+
const baseName = stripTrailingDigits(label);
|
|
266129
|
+
if (baseName.length > 5) {
|
|
266130
|
+
throw new Error(`Invalid governance label: base name must be 5 characters or fewer (got ${baseName.length})`);
|
|
266131
|
+
}
|
|
266132
|
+
}
|
|
266133
|
+
var isValidSubstrateAddress = (address, ss58Format = 42) => {
|
|
266134
|
+
try {
|
|
266135
|
+
if (isHex(address))
|
|
266136
|
+
return false;
|
|
266137
|
+
const decoded = decodeAddress2(address);
|
|
266138
|
+
const checksummed = encodeAddress2(decoded, ss58Format);
|
|
266139
|
+
return address === checksummed;
|
|
266140
|
+
} catch {
|
|
266141
|
+
return false;
|
|
266142
|
+
}
|
|
266143
|
+
};
|
|
266144
|
+
|
|
266145
|
+
// src/commands/lookup.ts
|
|
266146
|
+
init_contractInteractions();
|
|
266147
|
+
init_formatting();
|
|
266148
|
+
async function performDomainLookup(label, originSubstrateAddress, clientWrapper) {
|
|
266149
|
+
const fullyQualifiedDomainName = `${label}.dot`;
|
|
266150
|
+
const namehashNode = namehash(fullyQualifiedDomainName);
|
|
266151
|
+
const result = {
|
|
266152
|
+
domain: fullyQualifiedDomainName,
|
|
266153
|
+
node: namehashNode,
|
|
266154
|
+
exists: false,
|
|
266155
|
+
owner: zeroAddress,
|
|
266156
|
+
resolver: zeroAddress,
|
|
266157
|
+
store: null,
|
|
266158
|
+
resolvedAddress: null,
|
|
266159
|
+
ownerBalance: null,
|
|
266160
|
+
baseNameReservation: null
|
|
266161
|
+
};
|
|
266162
|
+
const spinner = ora("Reading registry").start();
|
|
266163
|
+
result.exists = Boolean(await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRY, DOTNS_REGISTRY_ABI, "recordExists", [namehashNode]));
|
|
266164
|
+
result.owner = getAddress(await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRY, DOTNS_REGISTRY_ABI, "owner", [namehashNode]));
|
|
266165
|
+
result.resolver = getAddress(await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRY, DOTNS_REGISTRY_ABI, "resolver", [namehashNode]));
|
|
266166
|
+
spinner.succeed("Registry read");
|
|
266167
|
+
console.log(`
|
|
266168
|
+
▶ DotNS Domain Lookup`);
|
|
266169
|
+
console.log(source_default.gray(" domain: ") + source_default.cyan(fullyQualifiedDomainName));
|
|
266170
|
+
console.log(source_default.gray(" node: ") + source_default.white(namehashNode));
|
|
266171
|
+
console.log();
|
|
266172
|
+
console.log("▶ Registry (DotnsRegistry)");
|
|
266173
|
+
console.log(source_default.gray(" registry: ") + source_default.white(CONTRACTS.DOTNS_REGISTRY));
|
|
266174
|
+
console.log(source_default.gray(" exists: ") + source_default.white(String(result.exists)));
|
|
266175
|
+
console.log(source_default.gray(" owner: ") + source_default.white(result.owner));
|
|
266176
|
+
console.log(source_default.gray(" resolver: ") + source_default.white(result.resolver));
|
|
266177
|
+
console.log();
|
|
266178
|
+
if (!result.exists || result.owner === zeroAddress) {
|
|
266179
|
+
console.log("▶ Status");
|
|
266180
|
+
console.log(source_default.gray(" status: ") + source_default.yellow("not registered (no record)"));
|
|
266181
|
+
console.log();
|
|
266182
|
+
const baseName2 = stripTrailingDigits(label);
|
|
266183
|
+
if (baseName2 !== label) {
|
|
266184
|
+
result.baseNameReservation = await lookupBaseNameReservation(clientWrapper, originSubstrateAddress, baseName2);
|
|
266185
|
+
displayBaseNameReservation(result.baseNameReservation);
|
|
266186
|
+
}
|
|
266187
|
+
return result;
|
|
266188
|
+
}
|
|
266189
|
+
console.log("▶ User Store (StoreFactory)");
|
|
266190
|
+
console.log(source_default.gray(" factory: ") + source_default.white(CONTRACTS.STORE_FACTORY));
|
|
266191
|
+
const storeAddress = getAddress(await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.STORE_FACTORY, STORE_FACTORY_ABI, "getDeployedStore", [result.owner]));
|
|
266192
|
+
result.store = storeAddress === zeroAddress ? null : storeAddress;
|
|
266193
|
+
console.log(source_default.gray(" store: ") + source_default.white(storeAddress));
|
|
266194
|
+
console.log(source_default.gray(" status: ") + source_default.white(storeAddress === zeroAddress ? "no store deployed" : "store exists"));
|
|
266195
|
+
console.log();
|
|
266196
|
+
console.log("▶ Forward Resolution (DotnsResolver)");
|
|
266197
|
+
console.log(source_default.gray(" expectedResolver: ") + source_default.white(CONTRACTS.DOTNS_RESOLVER));
|
|
266198
|
+
if (checksumAddress(result.resolver) !== checksumAddress(CONTRACTS.DOTNS_RESOLVER)) {
|
|
266199
|
+
console.log(source_default.gray(" note: ") + source_default.yellow("registry resolver is not DotnsResolver, skipping address lookup"));
|
|
266200
|
+
} else {
|
|
266201
|
+
try {
|
|
266202
|
+
const resolvedAddress = getAddress(await performContractCall(clientWrapper, originSubstrateAddress, result.resolver, DOTNS_RESOLVER_ABI, "addressOf", [namehashNode]));
|
|
266203
|
+
result.resolvedAddress = resolvedAddress === zeroAddress ? null : resolvedAddress;
|
|
266204
|
+
console.log(source_default.gray(" resolvedAddress: ") + source_default.white(resolvedAddress === zeroAddress ? "(not set)" : resolvedAddress));
|
|
266205
|
+
} catch {
|
|
266206
|
+
console.log(source_default.gray(" resolvedAddress: ") + source_default.yellow("lookup failed"));
|
|
266207
|
+
}
|
|
266208
|
+
}
|
|
266209
|
+
console.log();
|
|
266210
|
+
console.log("▶ Owner Balance");
|
|
266211
|
+
try {
|
|
266212
|
+
const ownerSubstrateAddress = await clientWrapper.getSubstrateAddress(result.owner);
|
|
266213
|
+
const accountInfo = await clientWrapper.client.query.System.Account.getValue(ownerSubstrateAddress);
|
|
266214
|
+
const freeBalance = accountInfo.data.free;
|
|
266215
|
+
result.ownerBalance = {
|
|
266216
|
+
substrate: ownerSubstrateAddress,
|
|
266217
|
+
free: formatNativeBalance(freeBalance)
|
|
266218
|
+
};
|
|
266219
|
+
console.log(source_default.gray(" substrate: ") + source_default.white(ownerSubstrateAddress));
|
|
266220
|
+
console.log(source_default.gray(" free: ") + source_default.white(formatNativeBalance(freeBalance) + " PAS"));
|
|
266221
|
+
} catch {
|
|
266222
|
+
console.log(source_default.gray(" balance: ") + source_default.yellow("unavailable"));
|
|
266223
|
+
}
|
|
266224
|
+
console.log();
|
|
266225
|
+
const baseName = stripTrailingDigits(label);
|
|
266226
|
+
if (baseName !== label) {
|
|
266227
|
+
result.baseNameReservation = await lookupBaseNameReservation(clientWrapper, originSubstrateAddress, baseName);
|
|
266228
|
+
displayBaseNameReservation(result.baseNameReservation);
|
|
266229
|
+
}
|
|
266230
|
+
console.log("▶ Lookup completed");
|
|
266231
|
+
return result;
|
|
266232
|
+
}
|
|
266233
|
+
async function lookupBaseNameReservation(clientWrapper, originSubstrateAddress, baseName) {
|
|
266234
|
+
try {
|
|
266235
|
+
const reservationInfo = await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_RULES, POP_RULES_ABI, "isBaseNameReserved", [baseName]);
|
|
266236
|
+
const [isReserved, reservationOwner, expirationTimestamp] = reservationInfo;
|
|
266237
|
+
return {
|
|
266238
|
+
baseName,
|
|
266239
|
+
isReserved,
|
|
266240
|
+
reservedBy: getAddress(reservationOwner),
|
|
266241
|
+
expires: expirationTimestamp > 0n ? new Date(Number(expirationTimestamp) * 1000).toISOString() : null
|
|
266242
|
+
};
|
|
266243
|
+
} catch {
|
|
266244
|
+
return {
|
|
266245
|
+
expires: null,
|
|
266246
|
+
baseName,
|
|
266247
|
+
isReserved: false,
|
|
266248
|
+
reservedBy: zeroAddress
|
|
266249
|
+
};
|
|
266250
|
+
}
|
|
266251
|
+
}
|
|
266252
|
+
function displayBaseNameReservation(reservation) {
|
|
266253
|
+
console.log("▶ Base Name Reservation (PopRules)");
|
|
266254
|
+
console.log(source_default.gray(" oracle: ") + source_default.white(CONTRACTS.DOTNS_RULES));
|
|
266255
|
+
console.log(source_default.gray(" baseName: ") + source_default.cyan(reservation.baseName));
|
|
266256
|
+
console.log(source_default.gray(" isReserved: ") + source_default.white(String(reservation.isReserved)));
|
|
266257
|
+
console.log(source_default.gray(" owner: ") + source_default.white(reservation.reservedBy));
|
|
266258
|
+
if (reservation.expires) {
|
|
266259
|
+
console.log(source_default.gray(" expires: ") + source_default.white(reservation.expires));
|
|
266260
|
+
}
|
|
266261
|
+
console.log();
|
|
266262
|
+
}
|
|
266263
|
+
async function performOwnerOfLookup(name10, substrateAddress, clientWrapper) {
|
|
266264
|
+
if (!name10 || name10.trim().length === 0) {
|
|
266265
|
+
throw new Error("--owner-of requires a <label>");
|
|
266266
|
+
}
|
|
266267
|
+
const label = name10.trim();
|
|
266268
|
+
console.log(source_default.bold(`
|
|
266269
|
+
\uD83D\uDD0E Ownership lookup
|
|
266270
|
+
`));
|
|
266271
|
+
console.log(source_default.gray(" Label: ") + source_default.cyan(label));
|
|
266272
|
+
console.log(source_default.gray(" Domain: ") + source_default.cyan(label + ".dot"));
|
|
266273
|
+
const tokenId = computeDomainTokenId(label);
|
|
266274
|
+
let actualOwner;
|
|
266275
|
+
let isRegistered;
|
|
266276
|
+
try {
|
|
266277
|
+
actualOwner = await withTimeout(performContractCall(clientWrapper, substrateAddress, CONTRACTS.DOTNS_REGISTRAR, DOTNS_REGISTRAR_ABI, "ownerOf", [tokenId]), 30000, "ownerOf");
|
|
266278
|
+
isRegistered = actualOwner !== zeroAddress;
|
|
266279
|
+
} catch (error2) {
|
|
266280
|
+
const errorMessage = formatErrorMessage(error2);
|
|
266281
|
+
if (errorMessage.includes("Contract reverted") || errorMessage.includes("does not exist")) {
|
|
266282
|
+
actualOwner = zeroAddress;
|
|
266283
|
+
isRegistered = false;
|
|
266284
|
+
} else {
|
|
266285
|
+
throw error2;
|
|
266286
|
+
}
|
|
266287
|
+
}
|
|
266288
|
+
const ownerSubstrateAddress = isRegistered ? await clientWrapper.getSubstrateAddress(actualOwner) : "(none)";
|
|
266289
|
+
console.log(source_default.gray(`
|
|
266290
|
+
Registered: `) + source_default.white(String(isRegistered)));
|
|
266291
|
+
console.log(source_default.gray(" Owner (EVM): ") + source_default.white(isRegistered ? actualOwner : "(none)"));
|
|
266292
|
+
console.log(source_default.gray(" Owner (Substrate): ") + source_default.white(ownerSubstrateAddress));
|
|
266293
|
+
return {
|
|
266294
|
+
label,
|
|
266295
|
+
domain: `${label}.dot`,
|
|
266296
|
+
registered: isRegistered,
|
|
266297
|
+
ownerEvm: isRegistered ? actualOwner : zeroAddress,
|
|
266298
|
+
ownerSubstrate: ownerSubstrateAddress
|
|
266299
|
+
};
|
|
266300
|
+
}
|
|
266301
|
+
|
|
266302
|
+
// src/commands/register.ts
|
|
266303
|
+
init_source();
|
|
266304
|
+
init_ora();
|
|
266305
|
+
init__esm();
|
|
266306
|
+
init_formatting();
|
|
266307
|
+
import crypto16 from "crypto";
|
|
266308
|
+
|
|
266309
|
+
// src/types/types.ts
|
|
266310
|
+
var ProofOfPersonhoodStatus;
|
|
266311
|
+
((ProofOfPersonhoodStatus2) => {
|
|
266312
|
+
ProofOfPersonhoodStatus2[ProofOfPersonhoodStatus2["NoStatus"] = 0] = "NoStatus";
|
|
266313
|
+
ProofOfPersonhoodStatus2[ProofOfPersonhoodStatus2["ProofOfPersonhoodLite"] = 1] = "ProofOfPersonhoodLite";
|
|
266314
|
+
ProofOfPersonhoodStatus2[ProofOfPersonhoodStatus2["ProofOfPersonhoodFull"] = 2] = "ProofOfPersonhoodFull";
|
|
266315
|
+
ProofOfPersonhoodStatus2[ProofOfPersonhoodStatus2["Reserved"] = 3] = "Reserved";
|
|
266316
|
+
})(ProofOfPersonhoodStatus ||= {});
|
|
266317
|
+
|
|
266318
|
+
// src/commands/register.ts
|
|
266319
|
+
init_constants();
|
|
266320
|
+
init_contractInteractions();
|
|
266321
|
+
init_formatting();
|
|
266322
|
+
function redactSecret(secret) {
|
|
266323
|
+
if (secret.length <= 10)
|
|
266324
|
+
return "0x" + "*".repeat(secret.length - 2);
|
|
266325
|
+
const prefix = secret.slice(0, 6);
|
|
266326
|
+
const suffix = secret.slice(-4);
|
|
266327
|
+
const redacted = "*".repeat(secret.length - 10);
|
|
266328
|
+
return `${prefix}${redacted}${suffix}`;
|
|
266329
|
+
}
|
|
266330
|
+
function convertToProofOfPersonhoodStatus(value3) {
|
|
266331
|
+
if (typeof value3 === "number")
|
|
266332
|
+
return value3;
|
|
266333
|
+
if (typeof value3 === "bigint")
|
|
266334
|
+
return Number(value3);
|
|
266335
|
+
throw new Error(`Unexpected ProofOfPersonhoodStatus type: ${typeof value3}`);
|
|
266336
|
+
}
|
|
266337
|
+
async function classifyDomainName(clientWrapper, originSubstrateAddress, label) {
|
|
266338
|
+
const spinner = ora("Classifying name via PopRules").start();
|
|
266339
|
+
try {
|
|
266340
|
+
const classificationResult = await withTimeout(performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_RULES, POP_RULES_ABI, "classifyName", [label]), 30000, "classifyName");
|
|
266341
|
+
const requiredStatus = convertToProofOfPersonhoodStatus(classificationResult[0]);
|
|
266342
|
+
const message2 = classificationResult[1];
|
|
266343
|
+
spinner.succeed("Name classification");
|
|
266344
|
+
console.log(source_default.gray(" required: ") + source_default.white(ProofOfPersonhoodStatus[requiredStatus]));
|
|
266345
|
+
console.log(source_default.gray(" message: ") + source_default.white(message2));
|
|
266346
|
+
return { requiredStatus, message: message2 };
|
|
266347
|
+
} catch (error2) {
|
|
266348
|
+
spinner.fail("Name classification failed");
|
|
266349
|
+
throw error2;
|
|
266350
|
+
}
|
|
266351
|
+
}
|
|
266352
|
+
async function ensureDomainNotRegistered(clientWrapper, originSubstrateAddress, label) {
|
|
266353
|
+
const spinner = ora(`Checking availability of ${source_default.cyan(label + ".dot")}`).start();
|
|
266354
|
+
const tokenId = computeDomainTokenId(label);
|
|
266355
|
+
try {
|
|
266356
|
+
const owner = await withTimeout(performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRAR, DOTNS_REGISTRAR_ABI, "ownerOf", [tokenId]), 30000, "Availability check");
|
|
266357
|
+
if (owner !== zeroAddress) {
|
|
266358
|
+
spinner.fail(`Name ${source_default.cyan(label + ".dot")} already owned by ${source_default.yellow(owner)}`);
|
|
266359
|
+
throw new Error(`Domain already owned by ${owner}`);
|
|
266360
|
+
}
|
|
266361
|
+
} catch (error2) {
|
|
266362
|
+
const errorMessage = formatErrorMessage(error2);
|
|
266363
|
+
if (errorMessage.includes("already owned"))
|
|
266364
|
+
throw error2;
|
|
266365
|
+
}
|
|
266366
|
+
spinner.succeed(`Name ${source_default.cyan(label + ".dot")} is available`);
|
|
266367
|
+
}
|
|
266368
|
+
async function generateCommitment(clientWrapper, originSubstrateAddress, label, ownerAddress, includeReverse) {
|
|
266369
|
+
const spinner = ora("Generating commitment hash").start();
|
|
266370
|
+
try {
|
|
266371
|
+
validateDomainLabel(label);
|
|
266372
|
+
const secret = `0x${crypto16.randomBytes(32).toString("hex")}`;
|
|
266373
|
+
const registration = {
|
|
266374
|
+
label,
|
|
266375
|
+
owner: ownerAddress,
|
|
266376
|
+
secret,
|
|
266377
|
+
reserved: includeReverse
|
|
266378
|
+
};
|
|
266379
|
+
const commitment = await withTimeout(performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRAR_CONTROLLER, DOTNS_REGISTRAR_CONTROLLER_ABI, "makeCommitment", [registration]), 30000, "Commitment generation");
|
|
266380
|
+
spinner.succeed("Commitment hash generated");
|
|
266381
|
+
console.log(source_default.gray(" commitment: ") + source_default.blue(commitment));
|
|
266382
|
+
console.log(source_default.gray(" hash: ") + source_default.dim("label + owner + secret + reserved"));
|
|
266383
|
+
console.log(source_default.gray(" secret: ") + source_default.yellow(redactSecret(secret)));
|
|
266384
|
+
console.log(source_default.gray(" reserved: ") + (includeReverse ? source_default.green("true") : source_default.white("false")));
|
|
266385
|
+
return { commitment, registration };
|
|
266386
|
+
} catch (error2) {
|
|
266387
|
+
spinner.fail("Failed to create commitment");
|
|
266388
|
+
throw error2;
|
|
266389
|
+
}
|
|
266390
|
+
}
|
|
266391
|
+
async function submitCommitment(clientWrapper, substrateAddress, signer, commitment) {
|
|
266392
|
+
const spinner = ora("Submitting commitment to controller").start();
|
|
266393
|
+
const transactionHash = await submitContractTransaction(clientWrapper, CONTRACTS.DOTNS_REGISTRAR_CONTROLLER, 0n, DOTNS_REGISTRAR_CONTROLLER_ABI, "commit", [commitment], substrateAddress, signer, spinner, "Commitment");
|
|
266394
|
+
console.log(source_default.gray(" tx: ") + source_default.blue(transactionHash));
|
|
266395
|
+
console.log(source_default.gray(" committed: ") + source_default.white(new Date().toISOString()));
|
|
266396
|
+
}
|
|
266397
|
+
async function waitForMinimumCommitmentAge(clientWrapper, originSubstrateAddress, commitment, commitmentBuffer) {
|
|
266398
|
+
const buffer2 = commitmentBuffer ?? DEFAULT_COMMITMENT_BUFFER_SECONDS;
|
|
266399
|
+
const checkSpinner = ora("Reading minimum commitment age").start();
|
|
266400
|
+
const [minimumAge, initialCommitTimestamp] = await Promise.all([
|
|
266401
|
+
withTimeout(performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRAR_CONTROLLER, DOTNS_REGISTRAR_CONTROLLER_ABI, "minCommitmentAge", []), 30000, "minCommitmentAge"),
|
|
266402
|
+
withTimeout(performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRAR_CONTROLLER, DOTNS_REGISTRAR_CONTROLLER_ABI, "commitments", [commitment]), 30000, "commitments")
|
|
266403
|
+
]);
|
|
266404
|
+
const minimumAgeSeconds = typeof minimumAge === "bigint" ? Number(minimumAge) : minimumAge;
|
|
266405
|
+
const initialCommitTime = typeof initialCommitTimestamp === "bigint" ? Number(initialCommitTimestamp) : initialCommitTimestamp;
|
|
266406
|
+
if (initialCommitTime === 0) {
|
|
266407
|
+
checkSpinner.fail("Commitment not found on-chain");
|
|
266408
|
+
throw new Error("Commitment not found on-chain. It may not have been included in a block yet.");
|
|
266409
|
+
}
|
|
266410
|
+
const waitSeconds = minimumAgeSeconds + buffer2;
|
|
266411
|
+
checkSpinner.succeed(`Minimum commitment age: ${source_default.yellow(waitSeconds.toString() + "s")}`);
|
|
266412
|
+
const waitSpinner = ora(`Waiting for commitment age (${waitSeconds}s)`).start();
|
|
266413
|
+
let elapsedSeconds = 0;
|
|
266414
|
+
const intervalId = setInterval(() => {
|
|
266415
|
+
elapsedSeconds++;
|
|
266416
|
+
const remainingSeconds = waitSeconds - elapsedSeconds;
|
|
266417
|
+
waitSpinner.text = `Waiting for commitment age (${source_default.yellow(remainingSeconds + "s")} remaining)`;
|
|
266418
|
+
}, 1000);
|
|
266419
|
+
await new Promise((resolve) => setTimeout(resolve, waitSeconds * 1000));
|
|
266420
|
+
clearInterval(intervalId);
|
|
266421
|
+
waitSpinner.text = "Verifying commitment age on-chain";
|
|
266422
|
+
const pollDeadline = Date.now() + COMMITMENT_POLL_TIMEOUT_MS;
|
|
266423
|
+
while (Date.now() < pollDeadline) {
|
|
266424
|
+
const polledTimestamp = await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRAR_CONTROLLER, DOTNS_REGISTRAR_CONTROLLER_ABI, "commitments", [commitment]);
|
|
266425
|
+
const polledCommitTime = typeof polledTimestamp === "bigint" ? Number(polledTimestamp) : polledTimestamp;
|
|
266426
|
+
const nowSeconds = Math.floor(Date.now() / 1000);
|
|
266427
|
+
if (polledCommitTime > 0 && nowSeconds - polledCommitTime >= minimumAgeSeconds) {
|
|
266428
|
+
waitSpinner.succeed("Commitment age requirement met (verified on-chain)");
|
|
266429
|
+
return;
|
|
266430
|
+
}
|
|
266431
|
+
waitSpinner.text = `Commitment still too new, polling (${Math.ceil((pollDeadline - Date.now()) / 1000)}s remaining)`;
|
|
266432
|
+
await new Promise((resolve) => setTimeout(resolve, COMMITMENT_POLL_INTERVAL_MS));
|
|
266433
|
+
}
|
|
266434
|
+
waitSpinner.fail("Commitment age verification timed out");
|
|
266435
|
+
throw new Error(`Commitment still too new after ${waitSeconds + COMMITMENT_POLL_TIMEOUT_MS / 1000}s. The chain's block timestamps may be advancing slower than expected. Try increasing --commitment-buffer or DOTNS_COMMITMENT_BUFFER.`);
|
|
266436
|
+
}
|
|
266437
|
+
async function getUserProofOfPersonhoodStatus(clientWrapper, originSubstrateAddress, ownerAddress) {
|
|
266438
|
+
const userStatusRaw = await withTimeout(performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_RULES, POP_RULES_ABI, "userPopStatus", [ownerAddress]), 30000, "userPopStatus");
|
|
266439
|
+
return convertToProofOfPersonhoodStatus(userStatusRaw);
|
|
266440
|
+
}
|
|
266441
|
+
async function getPriceAndValidateEligibility(clientWrapper, originSubstrateAddress, label, ownerAddress) {
|
|
266442
|
+
const spinner = ora("Pricing via PopRules.price").start();
|
|
266443
|
+
try {
|
|
266444
|
+
validateDomainLabel(label);
|
|
266445
|
+
const baseName = stripTrailingDigits(label);
|
|
266446
|
+
const reservationInfo = await withTimeout(performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_RULES, POP_RULES_ABI, "isBaseNameReserved", [baseName]), 30000, "isBaseNameReserved");
|
|
266447
|
+
const [isReserved, reservationOwner] = reservationInfo;
|
|
266448
|
+
if (isReserved && checksumAddress(reservationOwner) !== checksumAddress(ownerAddress)) {
|
|
266449
|
+
spinner.fail("Eligibility failed");
|
|
266450
|
+
throw new Error("Base name reserved for original Lite registrant");
|
|
266451
|
+
}
|
|
266452
|
+
const classificationResult = await withTimeout(performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_RULES, POP_RULES_ABI, "priceWithoutCheck", [label, ownerAddress]), 30000, "priceWithoutCheck");
|
|
266453
|
+
const requiredStatus = convertToProofOfPersonhoodStatus(classificationResult.status);
|
|
266454
|
+
const message2 = classificationResult.message;
|
|
266455
|
+
const userStatus = await getUserProofOfPersonhoodStatus(clientWrapper, originSubstrateAddress, ownerAddress);
|
|
266456
|
+
if (requiredStatus === 3 /* Reserved */) {
|
|
266457
|
+
spinner.fail("Eligibility failed");
|
|
266458
|
+
throw new Error(message2);
|
|
266459
|
+
}
|
|
266460
|
+
if (requiredStatus === 2 /* ProofOfPersonhoodFull */) {
|
|
266461
|
+
if (userStatus !== 2 /* ProofOfPersonhoodFull */) {
|
|
266462
|
+
spinner.fail("Eligibility failed");
|
|
266463
|
+
throw new Error("Requires Full Personhood verification");
|
|
266464
|
+
}
|
|
266465
|
+
} else if (requiredStatus === 1 /* ProofOfPersonhoodLite */) {
|
|
266466
|
+
if (userStatus !== 1 /* ProofOfPersonhoodLite */ && userStatus !== 2 /* ProofOfPersonhoodFull */) {
|
|
266467
|
+
spinner.fail("Eligibility failed");
|
|
266468
|
+
throw new Error("Requires Personhood Lite verification");
|
|
266469
|
+
}
|
|
266470
|
+
} else {
|
|
266471
|
+
const trailingDigitCount = countTrailingDigits(label);
|
|
266472
|
+
if (trailingDigitCount === 0 || userStatus === 1 /* ProofOfPersonhoodLite */) {
|
|
266473
|
+
spinner.fail("Eligibility failed");
|
|
266474
|
+
throw new Error(`Personhood Lite cannot register base names
|
|
266475
|
+
This means another user already owns the name without digits`);
|
|
266476
|
+
}
|
|
266477
|
+
}
|
|
266478
|
+
spinner.succeed("Eligibility and price");
|
|
266479
|
+
console.log(source_default.gray(" required: ") + source_default.white(ProofOfPersonhoodStatus[requiredStatus]));
|
|
266480
|
+
console.log(source_default.gray(" user: ") + source_default.white(ProofOfPersonhoodStatus[userStatus]));
|
|
266481
|
+
console.log(source_default.gray(" message: ") + source_default.white(message2));
|
|
266482
|
+
console.log(source_default.gray(" price: ") + source_default.green(`${classificationResult.priceWei > 0n ? formatWeiAsEther(classificationResult.priceWei) : 0n} PAS`));
|
|
266483
|
+
return {
|
|
266484
|
+
priceWei: classificationResult.price ?? classificationResult.priceWei,
|
|
266485
|
+
requiredStatus,
|
|
266486
|
+
userStatus,
|
|
266487
|
+
message: message2,
|
|
266488
|
+
status: requiredStatus,
|
|
266489
|
+
price: classificationResult.price ?? classificationResult.priceWei
|
|
266490
|
+
};
|
|
266491
|
+
} catch (error2) {
|
|
266492
|
+
if (!spinner.isSpinning)
|
|
266493
|
+
throw error2;
|
|
266494
|
+
spinner.fail("Pricing failed");
|
|
266495
|
+
throw error2;
|
|
266496
|
+
}
|
|
266497
|
+
}
|
|
266498
|
+
async function finalizeRegularRegistration(clientWrapper, substrateAddress, signer, registration, priceWei) {
|
|
266499
|
+
const spinner = ora(`Registering ${source_default.cyan(registration.label + ".dot")}`).start();
|
|
266500
|
+
try {
|
|
266501
|
+
const bufferedPaymentWei = priceWei * 110n / 100n;
|
|
266502
|
+
const bufferedPaymentNative = convertWeiToNative(bufferedPaymentWei);
|
|
266503
|
+
console.log(source_default.gray(" oracle: ") + source_default.green(formatWeiAsEther(priceWei) + " PAS"));
|
|
266504
|
+
console.log(source_default.gray(" paying: ") + source_default.green(formatWeiAsEther(bufferedPaymentWei) + " PAS"));
|
|
266505
|
+
const transactionHash = await submitContractTransaction(clientWrapper, CONTRACTS.DOTNS_REGISTRAR_CONTROLLER, bufferedPaymentNative, DOTNS_REGISTRAR_CONTROLLER_ABI, "register", [registration], substrateAddress, signer, spinner, "Registration");
|
|
266506
|
+
console.log(source_default.gray(" tx: ") + source_default.blue(transactionHash));
|
|
266507
|
+
console.log(source_default.gray(" paid: ") + source_default.green(formatWeiAsEther(bufferedPaymentWei) + " PAS"));
|
|
266508
|
+
} catch (error2) {
|
|
266509
|
+
spinner.fail("Registration failed");
|
|
266510
|
+
throw error2;
|
|
266511
|
+
}
|
|
266512
|
+
}
|
|
266513
|
+
async function finalizeGovernanceRegistration(clientWrapper, substrateAddress, signer, registration) {
|
|
266514
|
+
const spinner = ora(`Registering governance name ${source_default.cyan(registration.label + ".dot")}`).start();
|
|
266515
|
+
try {
|
|
266516
|
+
const transactionHash = await submitContractTransaction(clientWrapper, CONTRACTS.DOTNS_REGISTRAR_CONTROLLER, 0n, DOTNS_REGISTRAR_CONTROLLER_ABI, "registerReserved", [registration], substrateAddress, signer, spinner, "Governance Registration");
|
|
266517
|
+
console.log(source_default.gray(" tx: ") + source_default.blue(transactionHash));
|
|
266518
|
+
} catch (error2) {
|
|
266519
|
+
spinner.fail("Governance registration failed");
|
|
266520
|
+
throw error2;
|
|
266521
|
+
}
|
|
266522
|
+
}
|
|
266523
|
+
async function registerSubnode(clientWrapper, substrateAddress, signer, sublabel, parentLabel, ownerAddress) {
|
|
266524
|
+
const fullName = `${sublabel}.${parentLabel}.dot`;
|
|
266525
|
+
const spinner = ora(`Registering subname ${source_default.cyan(fullName)}`).start();
|
|
266526
|
+
try {
|
|
266527
|
+
const parentNode = namehash(`${parentLabel}.dot`);
|
|
266528
|
+
const subnodeRecord = {
|
|
266529
|
+
parentNode,
|
|
266530
|
+
subLabel: sublabel,
|
|
266531
|
+
parentLabel,
|
|
266532
|
+
owner: ownerAddress
|
|
266533
|
+
};
|
|
266534
|
+
const transactionHash = await submitContractTransaction(clientWrapper, CONTRACTS.DOTNS_REGISTRY, 0n, DOTNS_REGISTRY_ABI, "setSubnodeOwner", [subnodeRecord], substrateAddress, signer, spinner, "Subname registration");
|
|
266535
|
+
console.log(source_default.gray(" tx: ") + source_default.blue(transactionHash));
|
|
266536
|
+
return transactionHash;
|
|
266537
|
+
} catch (error2) {
|
|
266538
|
+
spinner.fail("Subname registration failed");
|
|
266539
|
+
throw error2;
|
|
266540
|
+
}
|
|
266541
|
+
}
|
|
266542
|
+
async function verifyDomainOwnership(clientWrapper, originSubstrateAddress, label, expectedOwner) {
|
|
266543
|
+
const spinner = ora("Verifying minted ownership").start();
|
|
266544
|
+
try {
|
|
266545
|
+
const tokenId = computeDomainTokenId(label);
|
|
266546
|
+
const actualOwner = await withTimeout(performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRAR, DOTNS_REGISTRAR_ABI, "ownerOf", [tokenId]), 30000, "ownerOf");
|
|
266547
|
+
if (checksumAddress(actualOwner) !== checksumAddress(expectedOwner)) {
|
|
266548
|
+
spinner.fail("Ownership verification failed");
|
|
266549
|
+
console.log(source_default.gray(" expected: ") + source_default.white(expectedOwner));
|
|
266550
|
+
console.log(source_default.gray(" actual: ") + source_default.white(actualOwner));
|
|
266551
|
+
throw new Error(`Owner mismatch for ${label}.dot`);
|
|
266552
|
+
}
|
|
266553
|
+
spinner.succeed("Ownership verified");
|
|
266554
|
+
console.log(source_default.gray(" owner: ") + source_default.white(actualOwner));
|
|
266555
|
+
return actualOwner;
|
|
266556
|
+
} catch (error2) {
|
|
266557
|
+
spinner.fail("Ownership verification failed");
|
|
266558
|
+
throw error2;
|
|
266559
|
+
}
|
|
266560
|
+
}
|
|
266561
|
+
async function displayDeployedStore(clientWrapper, originSubstrateAddress, ownerAddress) {
|
|
266562
|
+
const spinner = ora("Reading deployed Store address").start();
|
|
266563
|
+
try {
|
|
266564
|
+
const storeAddress = await withTimeout(performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.STORE_FACTORY, STORE_FACTORY_ABI, "getDeployedStore", [ownerAddress]), 30000, "getDeployedStore");
|
|
266565
|
+
spinner.succeed("Store");
|
|
266566
|
+
console.log(source_default.gray(" store: ") + (storeAddress === zeroAddress ? source_default.yellow("not deployed") : source_default.cyan(storeAddress)));
|
|
266567
|
+
} catch (error2) {
|
|
266568
|
+
spinner.fail("Failed to read Store address");
|
|
266569
|
+
throw error2;
|
|
266570
|
+
}
|
|
266571
|
+
}
|
|
266572
|
+
async function ensureStoreAuthorizations2(clientWrapper, substrateAddress, signer, evmAddress) {
|
|
266573
|
+
const storeAddress = getAddress(await withTimeout(performContractCall(clientWrapper, substrateAddress, CONTRACTS.STORE_FACTORY, STORE_FACTORY_ABI, "getDeployedStore", [evmAddress]), 30000, "getDeployedStore"));
|
|
266574
|
+
if (storeAddress === zeroAddress)
|
|
266575
|
+
return;
|
|
266576
|
+
const spinner = ora("Checking Store authorizations").start();
|
|
266577
|
+
const [controllerAuthorized, registryAuthorized] = await Promise.all([
|
|
266578
|
+
Boolean(await performContractCall(clientWrapper, substrateAddress, storeAddress, STORE_ABI, "isAuthorized", [CONTRACTS.DOTNS_REGISTRAR_CONTROLLER])),
|
|
266579
|
+
Boolean(await performContractCall(clientWrapper, substrateAddress, storeAddress, STORE_ABI, "isAuthorized", [CONTRACTS.DOTNS_REGISTRY]))
|
|
266580
|
+
]);
|
|
266581
|
+
if (controllerAuthorized && registryAuthorized) {
|
|
266582
|
+
spinner.succeed("Store authorizations verified");
|
|
266583
|
+
console.log(source_default.gray(" controller: ") + source_default.white(CONTRACTS.DOTNS_REGISTRAR_CONTROLLER));
|
|
266584
|
+
console.log(source_default.gray(" registry: ") + source_default.white(CONTRACTS.DOTNS_REGISTRY));
|
|
266585
|
+
return;
|
|
266586
|
+
}
|
|
266587
|
+
spinner.warn("Store authorizations need update");
|
|
266588
|
+
if (!controllerAuthorized) {
|
|
266589
|
+
const controllerSpinner = ora("Authorizing registrar controller as Store writer").start();
|
|
266590
|
+
const tx = await submitContractTransaction(clientWrapper, storeAddress, 0n, STORE_ABI, "authorizeStore", [CONTRACTS.DOTNS_REGISTRAR_CONTROLLER], substrateAddress, signer, controllerSpinner, "Authorize controller");
|
|
266591
|
+
console.log(source_default.gray(" tx: ") + source_default.blue(tx));
|
|
266592
|
+
console.log(source_default.gray(" controller: ") + source_default.white(CONTRACTS.DOTNS_REGISTRAR_CONTROLLER));
|
|
266593
|
+
}
|
|
266594
|
+
if (!registryAuthorized) {
|
|
266595
|
+
const registrySpinner = ora("Authorizing registry as Store writer").start();
|
|
266596
|
+
const tx = await submitContractTransaction(clientWrapper, storeAddress, 0n, STORE_ABI, "authorizeStore", [CONTRACTS.DOTNS_REGISTRY], substrateAddress, signer, registrySpinner, "Authorize registry");
|
|
266597
|
+
console.log(source_default.gray(" tx: ") + source_default.blue(tx));
|
|
266598
|
+
console.log(source_default.gray(" registry: ") + source_default.white(CONTRACTS.DOTNS_REGISTRY));
|
|
266599
|
+
}
|
|
266600
|
+
}
|
|
266601
|
+
async function setUserProofOfPersonhoodStatus(clientWrapper, substrateAddress, signer, ownerAddress, label, status) {
|
|
266602
|
+
const displayName = label ? source_default.cyan(label) : "account";
|
|
266603
|
+
const checkSpinner = ora(`Checking current PoP status for ${displayName}`).start();
|
|
266604
|
+
try {
|
|
266605
|
+
const currentStatus = await getUserProofOfPersonhoodStatus(clientWrapper, substrateAddress, ownerAddress);
|
|
266606
|
+
checkSpinner.succeed("Current PoP status");
|
|
266607
|
+
console.log(source_default.gray(" current: ") + source_default.white(ProofOfPersonhoodStatus[currentStatus]));
|
|
266608
|
+
console.log(source_default.gray(" desired: ") + source_default.white(ProofOfPersonhoodStatus[status]));
|
|
266609
|
+
if (currentStatus === status) {
|
|
266610
|
+
console.log(source_default.yellow(` ↳ Status already set to ${ProofOfPersonhoodStatus[status]}, skipping update`));
|
|
266611
|
+
return;
|
|
266612
|
+
}
|
|
266613
|
+
const updateSpinner = ora(`Setting PoP status for ${displayName} to ${source_default.yellow(ProofOfPersonhoodStatus[status])}`).start();
|
|
266614
|
+
const transactionHash = await submitContractTransaction(clientWrapper, CONTRACTS.DOTNS_RULES, 0n, POP_RULES_ABI, "setUserPopStatus", [status], substrateAddress, signer, updateSpinner, "PoP status update");
|
|
266615
|
+
console.log(source_default.gray(" tx: ") + source_default.blue(transactionHash));
|
|
266616
|
+
} catch (error2) {
|
|
266617
|
+
if (checkSpinner.isSpinning)
|
|
266618
|
+
checkSpinner.fail("Failed to check PoP status");
|
|
266619
|
+
throw error2;
|
|
266620
|
+
}
|
|
266621
|
+
}
|
|
266622
|
+
|
|
266623
|
+
// src/cli/commands/lookup.ts
|
|
266624
|
+
init_env();
|
|
266625
|
+
init_formatting();
|
|
266626
|
+
|
|
266627
|
+
// src/cli/transfer.ts
|
|
266628
|
+
init_source();
|
|
266629
|
+
init_ora();
|
|
266630
|
+
init__esm();
|
|
266631
|
+
init_constants();
|
|
266632
|
+
init_formatting();
|
|
266633
|
+
init_contractInteractions();
|
|
266634
|
+
function toChecksummed(a2) {
|
|
266635
|
+
return checksumAddress(a2);
|
|
266636
|
+
}
|
|
266637
|
+
function isLabelLike(input) {
|
|
266638
|
+
return /^[a-z0-9-]{3,}$/.test(input);
|
|
266639
|
+
}
|
|
266640
|
+
function asDotLabel(input) {
|
|
266641
|
+
const raw = input.trim().toLowerCase();
|
|
266642
|
+
if (raw.endsWith(".dot"))
|
|
266643
|
+
return raw.slice(0, -4);
|
|
266644
|
+
return raw;
|
|
266645
|
+
}
|
|
266646
|
+
async function ownerOfLabel(clientWrapper, originSubstrateAddress, label) {
|
|
266647
|
+
const tokenId = computeDomainTokenId(label);
|
|
266648
|
+
return await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRAR, DOTNS_REGISTRAR_ABI, "ownerOf", [tokenId]);
|
|
266649
|
+
}
|
|
266650
|
+
async function resolveTransferRecipient(clientWrapper, originSubstrateAddress, recipientIdentifier) {
|
|
266651
|
+
const input = recipientIdentifier.trim();
|
|
266652
|
+
if (isAddress(input))
|
|
266653
|
+
return toChecksummed(input);
|
|
266654
|
+
const label = asDotLabel(input);
|
|
266655
|
+
if (isLabelLike(label)) {
|
|
266656
|
+
const spinner2 = ora(`Resolving ${source_default.cyan(label + ".dot")} to owner address`).start();
|
|
266657
|
+
const ownerAddress = await ownerOfLabel(clientWrapper, originSubstrateAddress, label);
|
|
266658
|
+
if (ownerAddress === zeroAddress) {
|
|
266659
|
+
spinner2.fail(`No owner found for ${source_default.cyan(label + ".dot")} (unregistered)`);
|
|
266660
|
+
throw new Error(`Domain ${label}.dot has no owner`);
|
|
266661
|
+
}
|
|
266662
|
+
spinner2.succeed(`${source_default.cyan(label + ".dot")} → ${source_default.white(toChecksummed(ownerAddress))}`);
|
|
266663
|
+
return toChecksummed(ownerAddress);
|
|
266664
|
+
}
|
|
266665
|
+
const spinner = ora(`Resolving recipient address`).start();
|
|
266666
|
+
const evmAddress = await clientWrapper.getEvmAddress(input);
|
|
266667
|
+
spinner.succeed(`${source_default.white(input)} → ${source_default.white(toChecksummed(evmAddress))}`);
|
|
266668
|
+
return toChecksummed(evmAddress);
|
|
266669
|
+
}
|
|
266670
|
+
async function transferDomain(clientWrapper, originSubstrateAddress, signer, fromAddress, toAddress, label) {
|
|
266671
|
+
const spinner = ora().start();
|
|
266672
|
+
const normLabel = asDotLabel(label);
|
|
266673
|
+
spinner.text = `Validating ${source_default.cyan(normLabel + ".dot")}`;
|
|
266674
|
+
validateDomainLabel(normLabel);
|
|
266675
|
+
spinner.succeed(`Valid: ${source_default.cyan(normLabel + ".dot")}`);
|
|
266676
|
+
spinner.start(`Checking owner of ${source_default.cyan(normLabel + ".dot")}`);
|
|
266677
|
+
const tokenId = computeDomainTokenId(normLabel);
|
|
266678
|
+
const currentOwner = await ownerOfLabel(clientWrapper, originSubstrateAddress, normLabel);
|
|
266679
|
+
const currentOwnerC = toChecksummed(currentOwner);
|
|
266680
|
+
spinner.succeed(`Owner: ${source_default.cyan(normLabel + ".dot")} → ${source_default.white(currentOwnerC)}`);
|
|
266681
|
+
const fromC = toChecksummed(fromAddress);
|
|
266682
|
+
const toC = toChecksummed(toAddress);
|
|
266683
|
+
if (currentOwner === zeroAddress) {
|
|
266684
|
+
spinner.fail(`${source_default.cyan(normLabel + ".dot")} is not registered`);
|
|
266685
|
+
throw new Error(`Cannot transfer: ${normLabel}.dot is not registered`);
|
|
266686
|
+
}
|
|
266687
|
+
if (currentOwnerC !== fromC) {
|
|
266688
|
+
spinner.fail(`Not authorized to transfer ${source_default.cyan(normLabel + ".dot")}`);
|
|
266689
|
+
console.log(source_default.gray(" expected owner: ") + source_default.white(fromC));
|
|
266690
|
+
console.log(source_default.gray(" on-chain owner: ") + source_default.white(currentOwnerC));
|
|
266691
|
+
throw new Error(`Cannot transfer: ${normLabel}.dot owned by ${currentOwnerC}`);
|
|
266692
|
+
}
|
|
266693
|
+
try {
|
|
266694
|
+
const syncSpinner = ora(`Syncing label ${source_default.cyan(normLabel)} with registrar`).start();
|
|
266695
|
+
await submitContractTransaction(clientWrapper, CONTRACTS.DOTNS_REGISTRAR, 0n, DOTNS_REGISTRAR_ABI, "syncLabel", [tokenId, normLabel], originSubstrateAddress, signer, syncSpinner, "Label sync");
|
|
266696
|
+
syncSpinner.succeed("Label synced");
|
|
266697
|
+
} catch (error2) {
|
|
266698
|
+
const errorMessage = formatErrorMessage(error2);
|
|
266699
|
+
if (!errorMessage.includes("LabelAlreadySet")) {
|
|
266700
|
+
console.log(source_default.yellow(" Label sync skipped: " + errorMessage.split(`
|
|
266701
|
+
`)[0]));
|
|
266702
|
+
}
|
|
266703
|
+
}
|
|
266704
|
+
spinner.start(`Submitting transfer ${source_default.cyan(normLabel + ".dot")} → ${source_default.green(toC)}`);
|
|
266705
|
+
const transactionHash = await submitContractTransaction(clientWrapper, CONTRACTS.DOTNS_REGISTRAR, 0n, DOTNS_REGISTRAR_ABI, "transferFrom", [fromC, toC, tokenId], originSubstrateAddress, signer, spinner, "Transfer");
|
|
266706
|
+
spinner.succeed(`Transfer finalized`);
|
|
266707
|
+
console.log(source_default.gray(" tx: ") + source_default.blue(transactionHash));
|
|
266708
|
+
console.log(source_default.gray(" from: ") + source_default.yellow(fromC));
|
|
266709
|
+
console.log(source_default.gray(" to: ") + source_default.green(toC));
|
|
266710
|
+
console.log(source_default.gray(" name: ") + source_default.cyan(normLabel + ".dot"));
|
|
266711
|
+
}
|
|
266712
|
+
|
|
266713
|
+
// src/cli/commands/register.ts
|
|
266714
|
+
init_source();
|
|
266715
|
+
init__esm();
|
|
266716
|
+
|
|
266717
|
+
// src/cli/labels.ts
|
|
266718
|
+
function generateRandomLabel(status) {
|
|
266719
|
+
const alphabet4 = "abcdefghijklmnopqrstuvwxyz";
|
|
266720
|
+
const alphanumeric = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
266721
|
+
const randomInteger = (maxExclusive) => Math.floor(Math.random() * maxExclusive);
|
|
266722
|
+
const randomCharacters = (characterSet, count2) => {
|
|
266723
|
+
let result = "";
|
|
266724
|
+
for (let i2 = 0;i2 < count2; i2++)
|
|
266725
|
+
result += characterSet[randomInteger(characterSet.length)];
|
|
266726
|
+
return result;
|
|
266727
|
+
};
|
|
266728
|
+
const twoDigits = () => String(randomInteger(99) + 1).padStart(2, "0");
|
|
266729
|
+
const baseEndingWithLetter = (length5) => {
|
|
266730
|
+
if (length5 <= 0)
|
|
266731
|
+
throw new Error("Invalid base length");
|
|
266732
|
+
if (length5 === 1)
|
|
266733
|
+
return randomCharacters(alphabet4, 1);
|
|
266734
|
+
return randomCharacters(alphanumeric, length5 - 1) + randomCharacters(alphabet4, 1);
|
|
266735
|
+
};
|
|
266736
|
+
if (status === 1 /* ProofOfPersonhoodLite */) {
|
|
266737
|
+
const baseLength = 6 + randomInteger(3);
|
|
266738
|
+
return baseEndingWithLetter(baseLength) + twoDigits();
|
|
266739
|
+
}
|
|
266740
|
+
if (status === 0 /* NoStatus */) {
|
|
266741
|
+
const baseLength = 9 + randomInteger(6);
|
|
266742
|
+
return baseEndingWithLetter(baseLength) + twoDigits();
|
|
266743
|
+
}
|
|
266744
|
+
if (status === 2 /* ProofOfPersonhoodFull */) {
|
|
266745
|
+
const baseLength = randomInteger(2) === 0 ? 6 + randomInteger(3) : 9 + randomInteger(6);
|
|
266746
|
+
return baseEndingWithLetter(baseLength);
|
|
266747
|
+
}
|
|
266748
|
+
throw new Error("Cannot auto-generate Reserved names");
|
|
266749
|
+
}
|
|
266750
|
+
function parseProofOfPersonhoodStatus(statusString) {
|
|
266751
|
+
const normalized = statusString.toLowerCase();
|
|
266752
|
+
if (normalized === "none" || normalized === "nostatus")
|
|
266753
|
+
return 0 /* NoStatus */;
|
|
266754
|
+
if (normalized === "lite" || normalized === "poplite")
|
|
266755
|
+
return 1 /* ProofOfPersonhoodLite */;
|
|
266756
|
+
if (normalized === "full" || normalized === "popfull")
|
|
266757
|
+
return 2 /* ProofOfPersonhoodFull */;
|
|
266758
|
+
throw new Error("Invalid status: use none, lite, or full");
|
|
266759
|
+
}
|
|
266760
|
+
|
|
266761
|
+
// src/cli/commands/register.ts
|
|
266762
|
+
function resolveTransferDestination(options2) {
|
|
266763
|
+
const legacy = options2.transferTo;
|
|
266764
|
+
const modern = options2.to;
|
|
266765
|
+
const destination = legacy ?? modern;
|
|
266766
|
+
if (options2.transfer === true && !destination) {
|
|
266767
|
+
throw new Error("Missing transfer destination: use --to <evm|ss58|label>");
|
|
266768
|
+
}
|
|
266769
|
+
if (options2.transfer === false && legacy) {
|
|
266770
|
+
return legacy;
|
|
266771
|
+
}
|
|
266772
|
+
return destination;
|
|
266773
|
+
}
|
|
266774
|
+
function classifyTransferDestination(destination) {
|
|
266775
|
+
if (isAddress(destination))
|
|
266776
|
+
return "evm";
|
|
266777
|
+
if (isValidSubstrateAddress(destination))
|
|
266778
|
+
return "substrate";
|
|
266779
|
+
return "label";
|
|
266780
|
+
}
|
|
266781
|
+
function isValidTransferDestination(destination) {
|
|
266782
|
+
const kind = classifyTransferDestination(destination);
|
|
266783
|
+
if (kind === "evm" || kind === "substrate")
|
|
266784
|
+
return true;
|
|
266785
|
+
const domainLabelPattern = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;
|
|
266786
|
+
return domainLabelPattern.test(destination) && destination.length >= 3 && destination.length <= 63;
|
|
266787
|
+
}
|
|
266788
|
+
async function executeRegistration(options2 = {}) {
|
|
266789
|
+
if (options2.mnemonic && options2.keyUri) {
|
|
266790
|
+
throw new Error("Cannot specify both --mnemonic and --key-uri");
|
|
266791
|
+
}
|
|
266792
|
+
if (options2.parent) {
|
|
266793
|
+
return executeSubnameRegistration(options2);
|
|
266794
|
+
}
|
|
266795
|
+
const transferDestination = resolveTransferDestination(options2);
|
|
266796
|
+
if (transferDestination && !isValidTransferDestination(transferDestination)) {
|
|
266797
|
+
throw new Error("Invalid transfer destination: must be valid EVM address, Substrate address, or domain label");
|
|
266798
|
+
}
|
|
266799
|
+
const context = await prepareAssetHubContext(options2);
|
|
266800
|
+
const { clientWrapper, substrateAddress, signer, evmAddress } = context;
|
|
266801
|
+
const statusWasProvided = options2.__statusProvided === true;
|
|
266802
|
+
const popStatusConfig = statusWasProvided ? { mode: "set", status: parseProofOfPersonhoodStatus(options2.status ?? "none") } : { mode: "unchanged" };
|
|
266803
|
+
const label = options2.name ?? generateRandomLabel(popStatusConfig.mode === "set" ? popStatusConfig.status : 0 /* NoStatus */);
|
|
266804
|
+
console.log(source_default.gray(" Mode: ") + source_default.yellow(options2.governance ? "Governance registration" : "Regular registration"));
|
|
266805
|
+
console.log(source_default.gray(" Label: ") + source_default.cyan(label));
|
|
266806
|
+
console.log(source_default.gray(" Domain: ") + source_default.cyan(label + ".dot"));
|
|
266807
|
+
console.log(source_default.gray(" Transfer: ") + (transferDestination ? source_default.green("post-mint") : source_default.gray("none")));
|
|
266808
|
+
await step("Ensuring account mapped", async () => clientWrapper.ensureAccountMapped(substrateAddress, signer));
|
|
266809
|
+
if (options2.governance) {
|
|
266810
|
+
await executeGovernanceRegistration(clientWrapper, substrateAddress, signer, evmAddress, label, transferDestination, options2.commitmentBuffer);
|
|
266811
|
+
} else {
|
|
266812
|
+
await executeRegularRegistration(clientWrapper, substrateAddress, signer, evmAddress, label, popStatusConfig, options2.reverse ?? false, transferDestination, options2.commitmentBuffer);
|
|
266813
|
+
}
|
|
266814
|
+
console.log(`
|
|
266815
|
+
${source_default.bold.green("═══════════════════════════════════════")}`);
|
|
266816
|
+
console.log(`${source_default.bold.green(" ✓ Operation Complete ")}`);
|
|
266817
|
+
console.log(`${source_default.bold.green("═══════════════════════════════════════")}
|
|
266818
|
+
`);
|
|
266819
|
+
console.log(source_default.gray(" Domain: ") + source_default.cyan(label + ".dot"));
|
|
266820
|
+
return { ok: true, label, domain: `${label}.dot`, owner: evmAddress };
|
|
266821
|
+
}
|
|
266822
|
+
async function executeSubnameRegistration(options2) {
|
|
266823
|
+
if (!options2.name) {
|
|
266824
|
+
throw new Error("Missing subname: use --name <sublabel>");
|
|
266825
|
+
}
|
|
266826
|
+
if (!options2.parent) {
|
|
266827
|
+
throw new Error("Missing parent: use --parent <parentlabel>");
|
|
266828
|
+
}
|
|
266829
|
+
const context = await prepareAssetHubContext(options2);
|
|
266830
|
+
const { clientWrapper, substrateAddress, signer, evmAddress } = context;
|
|
266831
|
+
const sublabel = options2.name;
|
|
266832
|
+
const parentLabel = options2.parent;
|
|
266833
|
+
const ownerAddress = options2.owner ?? evmAddress;
|
|
266834
|
+
const fullName = `${sublabel}.${parentLabel}.dot`;
|
|
266835
|
+
console.log(source_default.bold(`
|
|
266836
|
+
▶ Subname Registration
|
|
266837
|
+
`));
|
|
266838
|
+
console.log(source_default.gray(" Subname: ") + source_default.cyan(fullName));
|
|
266839
|
+
console.log(source_default.gray(" Parent: ") + source_default.white(`${parentLabel}.dot`));
|
|
266840
|
+
console.log(source_default.gray(" Owner: ") + source_default.white(ownerAddress));
|
|
266841
|
+
await step("Ensuring account mapped", async () => clientWrapper.ensureAccountMapped(substrateAddress, signer));
|
|
266842
|
+
await registerSubnode(clientWrapper, substrateAddress, signer, sublabel, parentLabel, ownerAddress);
|
|
266843
|
+
console.log(`
|
|
266844
|
+
${source_default.bold.green("═══════════════════════════════════════")}`);
|
|
266845
|
+
console.log(`${source_default.bold.green(" ✓ Subname Registered ")}`);
|
|
266846
|
+
console.log(`${source_default.bold.green("═══════════════════════════════════════")}
|
|
266847
|
+
`);
|
|
266848
|
+
console.log(source_default.gray(" Domain: ") + source_default.cyan(fullName));
|
|
266849
|
+
return {
|
|
266850
|
+
ok: true,
|
|
266851
|
+
label: sublabel,
|
|
266852
|
+
parent: parentLabel,
|
|
266853
|
+
domain: fullName,
|
|
266854
|
+
owner: ownerAddress
|
|
266855
|
+
};
|
|
266856
|
+
}
|
|
266857
|
+
async function executeGovernanceRegistration(clientWrapper, substrateAddress, signer, evmAddress, label, transferDestination, commitmentBuffer) {
|
|
266858
|
+
console.log(source_default.bold(`
|
|
266859
|
+
\uD83C\uDFDB Governance registration (commit-reveal)
|
|
266860
|
+
`));
|
|
266861
|
+
validateGovernanceLabel(label);
|
|
266862
|
+
const classification = await step("Classifying name", async () => classifyDomainName(clientWrapper, substrateAddress, label));
|
|
266863
|
+
if (classification.requiredStatus !== 3 /* Reserved */) {
|
|
266864
|
+
throw new Error(`Governance name must classify as Reserved; got ${ProofOfPersonhoodStatus[classification.requiredStatus]}`);
|
|
266865
|
+
}
|
|
266866
|
+
await step("Checking availability", async () => ensureDomainNotRegistered(clientWrapper, substrateAddress, label));
|
|
266867
|
+
const { commitment, registration } = await step("Generating commitment", async () => generateCommitment(clientWrapper, substrateAddress, label, evmAddress, true));
|
|
266868
|
+
await step("Submitting commitment", async () => submitCommitment(clientWrapper, substrateAddress, signer, commitment));
|
|
266869
|
+
await step("Waiting commitment age", async () => waitForMinimumCommitmentAge(clientWrapper, substrateAddress, commitment, commitmentBuffer));
|
|
266870
|
+
await step("Finalizing registration", async () => finalizeGovernanceRegistration(clientWrapper, substrateAddress, signer, registration));
|
|
266871
|
+
await step("Verifying ownership", async () => verifyDomainOwnership(clientWrapper, substrateAddress, label, evmAddress));
|
|
266872
|
+
await step("Displaying store", async () => displayDeployedStore(clientWrapper, substrateAddress, evmAddress));
|
|
266873
|
+
await step("Ensuring store authorizations", async () => ensureStoreAuthorizations2(clientWrapper, substrateAddress, signer, evmAddress));
|
|
266874
|
+
if (transferDestination) {
|
|
266875
|
+
const recipient = await step("Resolving recipient", async () => resolveTransferRecipient(clientWrapper, substrateAddress, transferDestination));
|
|
266876
|
+
await step("Transferring domain", async () => transferDomain(clientWrapper, substrateAddress, signer, evmAddress, recipient, label));
|
|
266877
|
+
await step("Verifying ownership", async () => verifyDomainOwnership(clientWrapper, substrateAddress, label, recipient));
|
|
266878
|
+
}
|
|
266879
|
+
}
|
|
266880
|
+
async function executeRegularRegistration(clientWrapper, substrateAddress, signer, evmAddress, label, popStatusConfig, enableReverseRecord, transferDestination, commitmentBuffer) {
|
|
266881
|
+
console.log(source_default.bold(`
|
|
266882
|
+
\uD83E\uDDFE Regular registration (commit-reveal)
|
|
266883
|
+
`));
|
|
266884
|
+
validateDomainLabel(label);
|
|
266885
|
+
const classification = await step("Classifying name", async () => classifyDomainName(clientWrapper, substrateAddress, label));
|
|
266886
|
+
if (popStatusConfig.mode === "set") {
|
|
266887
|
+
await step("Setting PoP status", async () => setUserProofOfPersonhoodStatus(clientWrapper, substrateAddress, signer, evmAddress, label, popStatusConfig.status));
|
|
266888
|
+
}
|
|
266889
|
+
await step("Checking availability", async () => ensureDomainNotRegistered(clientWrapper, substrateAddress, label));
|
|
266890
|
+
const { commitment, registration } = await step("Generating commitment", async () => generateCommitment(clientWrapper, substrateAddress, label, evmAddress, enableReverseRecord));
|
|
266891
|
+
await step("Submitting commitment", async () => submitCommitment(clientWrapper, substrateAddress, signer, commitment));
|
|
266892
|
+
await step("Waiting commitment age", async () => waitForMinimumCommitmentAge(clientWrapper, substrateAddress, commitment, commitmentBuffer));
|
|
266893
|
+
const pricing = await step("Pricing and eligibility", async () => getPriceAndValidateEligibility(clientWrapper, substrateAddress, label, evmAddress));
|
|
266894
|
+
await step("Finalizing registration", async () => finalizeRegularRegistration(clientWrapper, substrateAddress, signer, registration, pricing.priceWei));
|
|
266895
|
+
await step("Verifying ownership", async () => verifyDomainOwnership(clientWrapper, substrateAddress, label, evmAddress));
|
|
266896
|
+
await step("Displaying store", async () => displayDeployedStore(clientWrapper, substrateAddress, evmAddress));
|
|
266897
|
+
await step("Ensuring store authorizations", async () => ensureStoreAuthorizations2(clientWrapper, substrateAddress, signer, evmAddress));
|
|
266898
|
+
if (transferDestination) {
|
|
266899
|
+
const recipient = await step("Resolving recipient", async () => resolveTransferRecipient(clientWrapper, substrateAddress, transferDestination));
|
|
266900
|
+
await step("Transferring domain", async () => transferDomain(clientWrapper, substrateAddress, signer, evmAddress, recipient, label));
|
|
266901
|
+
await step("Verifying ownership", async () => verifyDomainOwnership(clientWrapper, substrateAddress, label, recipient));
|
|
266902
|
+
}
|
|
266903
|
+
}
|
|
266904
|
+
|
|
266905
|
+
// src/cli/commands/lookup.ts
|
|
266906
|
+
function createClientWrapper(rpc) {
|
|
266907
|
+
const client = createClient3(getWsProvider(rpc)).getTypedApi(paseo_default);
|
|
266908
|
+
return new ReviveClientWrapper(client);
|
|
266909
|
+
}
|
|
266910
|
+
function hasAnyAuthHint(opts) {
|
|
266911
|
+
return opts.mnemonic != null && String(opts.mnemonic).length > 0 || opts.keyUri != null && String(opts.keyUri).length > 0 || opts.keystorePath != null && String(opts.keystorePath).length > 0 || opts.account != null && String(opts.account).length > 0 || opts.password != null && String(opts.password).length > 0;
|
|
266912
|
+
}
|
|
266913
|
+
function withReadOnlyPasswordFallback(opts) {
|
|
266914
|
+
const passwordEnv = process.env.DOTNS_KEYSTORE_PASSWORD;
|
|
266915
|
+
if ((opts.password == null || String(opts.password).length === 0) && passwordEnv && passwordEnv.length > 0) {
|
|
266916
|
+
return { ...opts, password: passwordEnv };
|
|
266917
|
+
}
|
|
266918
|
+
return opts;
|
|
266919
|
+
}
|
|
266920
|
+
async function prepareReadOnlyContext(options2) {
|
|
266921
|
+
const rpc = resolveRpc(options2.rpc);
|
|
266922
|
+
const clientWrapper = await step(`Connecting RPC ${rpc}`, async () => createClientWrapper(rpc));
|
|
266923
|
+
const auth = await step("Resolving read-only account", async () => {
|
|
266924
|
+
if (hasAnyAuthHint(options2)) {
|
|
266925
|
+
const merged = withReadOnlyPasswordFallback(options2);
|
|
266926
|
+
const resolved2 = await resolveAuthSource(merged);
|
|
266927
|
+
return {
|
|
266928
|
+
source: resolved2.source,
|
|
266929
|
+
isKeyUri: resolved2.isKeyUri,
|
|
266930
|
+
resolvedFrom: resolved2.resolvedFrom,
|
|
266931
|
+
account: resolved2.account
|
|
266932
|
+
};
|
|
266933
|
+
}
|
|
266934
|
+
const resolved = await resolveAuthSourceReadOnly();
|
|
266935
|
+
return {
|
|
266936
|
+
source: resolved.source,
|
|
266937
|
+
isKeyUri: resolved.isKeyUri,
|
|
266938
|
+
resolvedFrom: resolved.resolvedFrom,
|
|
266939
|
+
account: resolved.account
|
|
266940
|
+
};
|
|
266941
|
+
});
|
|
266942
|
+
const keypair3 = await step("Loading keypair", async () => createAccountFromSource(auth.source, auth.isKeyUri));
|
|
266943
|
+
const evmAddress = await step("Resolving EVM address", async () => clientWrapper.getEvmAddress(keypair3.address));
|
|
266944
|
+
console.log(source_default.gray(`
|
|
266945
|
+
RPC: `) + source_default.white(rpc));
|
|
266946
|
+
console.log(source_default.gray(" Account: ") + source_default.white(keypair3.address));
|
|
266947
|
+
return { clientWrapper, account: { address: keypair3.address }, rpc, evmAddress };
|
|
266948
|
+
}
|
|
266949
|
+
async function resolveRecipientByKind(clientWrapper, substrateAddress, destination) {
|
|
266950
|
+
const kind = classifyTransferDestination(destination);
|
|
266951
|
+
switch (kind) {
|
|
266952
|
+
case "evm":
|
|
266953
|
+
return destination;
|
|
266954
|
+
case "substrate":
|
|
266955
|
+
return clientWrapper.getEvmAddress(destination);
|
|
266956
|
+
case "label":
|
|
266957
|
+
return resolveTransferRecipient(clientWrapper, substrateAddress, destination);
|
|
266958
|
+
}
|
|
266959
|
+
}
|
|
266960
|
+
function attachLookupCommands(root) {
|
|
266961
|
+
const lookupCommand = root.command("lookup").description("Lookup domain information");
|
|
266962
|
+
addAuthOptions(lookupCommand);
|
|
266963
|
+
const lookupNameCommand = lookupCommand.command("name [label]").description("Lookup comprehensive domain information").option("-n, --name <label>", "Domain label to lookup (alternative to positional argument)").option("--json", "Output result as JSON (suppresses all other output)", false);
|
|
266964
|
+
addAuthOptions(lookupNameCommand).action(async (positionalLabel, options2, cmd) => {
|
|
266965
|
+
try {
|
|
266966
|
+
const merged = {
|
|
266967
|
+
...options2 ?? {},
|
|
266968
|
+
...getAuthOptions(cmd),
|
|
266969
|
+
__positionalLabel: positionalLabel
|
|
266970
|
+
};
|
|
266971
|
+
const label = merged.name || merged.__positionalLabel;
|
|
266972
|
+
const jsonOutput = getJsonFlag(cmd);
|
|
266973
|
+
if (!label) {
|
|
266974
|
+
if (jsonOutput) {
|
|
266975
|
+
console.error(JSON.stringify({ error: "Domain label is required" }));
|
|
266976
|
+
process.exit(1);
|
|
266757
266977
|
}
|
|
266978
|
+
console.error(source_default.red(`
|
|
266979
|
+
Error: Domain label is required
|
|
266980
|
+
`));
|
|
266981
|
+
console.log(source_default.gray("Usage: dotns lookup name <label>"));
|
|
266982
|
+
console.log(source_default.gray(" or: dotns lookup name --name <label>"));
|
|
266983
|
+
console.log(source_default.gray(` or: dotns lookup --name <label>
|
|
266984
|
+
`));
|
|
266985
|
+
process.exit(1);
|
|
266758
266986
|
}
|
|
266759
|
-
|
|
266760
|
-
|
|
266761
|
-
|
|
266762
|
-
|
|
266763
|
-
|
|
266764
|
-
|
|
266765
|
-
|
|
266987
|
+
const { clientWrapper, account } = await maybeQuiet(jsonOutput, () => prepareReadOnlyContext(merged));
|
|
266988
|
+
if (!jsonOutput)
|
|
266989
|
+
console.log(source_default.bold(`
|
|
266990
|
+
▶ Domain Lookup
|
|
266991
|
+
`));
|
|
266992
|
+
const result = await maybeQuiet(jsonOutput, () => performDomainLookup(label, account.address, clientWrapper));
|
|
266993
|
+
if (jsonOutput) {
|
|
266994
|
+
console.log(JSON.stringify(result));
|
|
266995
|
+
} else {
|
|
266996
|
+
console.log(source_default.green(`
|
|
266997
|
+
✓ Complete
|
|
266998
|
+
`));
|
|
266766
266999
|
}
|
|
266767
267000
|
process.exit(0);
|
|
266768
267001
|
} catch (error2) {
|
|
266769
267002
|
const errorMessage = formatErrorMessage(error2);
|
|
266770
|
-
const jsonOutput = getJsonFlag(
|
|
267003
|
+
const jsonOutput = getJsonFlag(cmd);
|
|
266771
267004
|
if (jsonOutput) {
|
|
266772
|
-
|
|
267005
|
+
console.error(JSON.stringify({ error: errorMessage }));
|
|
267006
|
+
process.exit(1);
|
|
266773
267007
|
}
|
|
266774
267008
|
console.error(source_default.red(`
|
|
266775
267009
|
✗ Error: ${errorMessage}
|
|
@@ -266777,61 +267011,35 @@ function attachBulletinCommands(root) {
|
|
|
266777
267011
|
process.exit(1);
|
|
266778
267012
|
}
|
|
266779
267013
|
});
|
|
266780
|
-
|
|
266781
|
-
|
|
266782
|
-
|
|
266783
|
-
|
|
266784
|
-
|
|
266785
|
-
|
|
266786
|
-
|
|
266787
|
-
|
|
266788
|
-
|
|
266789
|
-
|
|
266790
|
-
|
|
266791
|
-
|
|
266792
|
-
if (jsonOutput) {
|
|
266793
|
-
writeBulletinJson({
|
|
266794
|
-
address: targetAddress,
|
|
266795
|
-
rpc: bulletinRpc,
|
|
266796
|
-
authorized: authStatus.authorized,
|
|
266797
|
-
expired: authStatus.expired ?? false,
|
|
266798
|
-
transactions: authStatus.transactions ?? 0,
|
|
266799
|
-
bytes: (authStatus.bytes ?? BigInt(0)).toString(),
|
|
266800
|
-
expiresAt: expirationToISOString(authStatus.currentBlock, authStatus.expiration)
|
|
266801
|
-
});
|
|
266802
|
-
} else {
|
|
266803
|
-
console.log(source_default.blue(`
|
|
266804
|
-
▶ Bulletin Authorization Status`));
|
|
266805
|
-
console.log(source_default.gray(" account: ") + source_default.cyan(targetAddress));
|
|
266806
|
-
console.log(source_default.gray(" rpc: ") + source_default.white(bulletinRpc));
|
|
266807
|
-
if (!authStatus.authorized) {
|
|
266808
|
-
console.log(source_default.gray(" status: ") + source_default.red("not authorized"));
|
|
266809
|
-
console.log(source_default.gray(`
|
|
266810
|
-
Authorize with: dotns bulletin authorize ` + targetAddress + `
|
|
267014
|
+
lookupCommand.option("-n, --name <label>", "Domain label to lookup").option("--json", "Output result as JSON (suppresses all other output)", false).action(async (options2, cmd) => {
|
|
267015
|
+
const subcommand = cmd.args?.[0];
|
|
267016
|
+
if (["name", "owner-of", "oo", "transfer"].includes(subcommand))
|
|
267017
|
+
return;
|
|
267018
|
+
if (options2.name) {
|
|
267019
|
+
try {
|
|
267020
|
+
const merged = { ...options2 ?? {}, ...getAuthOptions(cmd) };
|
|
267021
|
+
const jsonOutput = getJsonFlag(cmd);
|
|
267022
|
+
const { clientWrapper, account } = await maybeQuiet(jsonOutput, () => prepareReadOnlyContext(merged));
|
|
267023
|
+
if (!jsonOutput)
|
|
267024
|
+
console.log(source_default.bold(`
|
|
267025
|
+
▶ Domain Lookup
|
|
266811
267026
|
`));
|
|
267027
|
+
const result = await maybeQuiet(jsonOutput, () => performDomainLookup(merged.name, account.address, clientWrapper));
|
|
267028
|
+
if (jsonOutput) {
|
|
267029
|
+
console.log(JSON.stringify(result));
|
|
266812
267030
|
} else {
|
|
266813
|
-
|
|
266814
|
-
|
|
266815
|
-
console.log(source_default.gray(" status: ") + (isExpired ? source_default.red("expired") : source_default.green("authorized")));
|
|
266816
|
-
console.log(source_default.gray(isExpired ? " expired: " : " expires: ") + (isExpired ? source_default.red(dateDisplay) : source_default.white(dateDisplay)));
|
|
266817
|
-
console.log(source_default.gray(" transactions: ") + source_default.white((authStatus.transactions ?? 0).toLocaleString()));
|
|
266818
|
-
console.log(source_default.gray(" bytes: ") + source_default.white(formatBytes(authStatus.bytes ?? BigInt(0))));
|
|
266819
|
-
if (isExpired) {
|
|
266820
|
-
console.log(source_default.gray(`
|
|
266821
|
-
Re-authorize with: dotns bulletin authorize ` + targetAddress + `
|
|
267031
|
+
console.log(source_default.green(`
|
|
267032
|
+
✓ Complete
|
|
266822
267033
|
`));
|
|
266823
|
-
} else {
|
|
266824
|
-
console.log();
|
|
266825
|
-
}
|
|
266826
267034
|
}
|
|
266827
|
-
|
|
266828
|
-
|
|
266829
|
-
|
|
266830
|
-
|
|
266831
|
-
|
|
266832
|
-
|
|
266833
|
-
|
|
266834
|
-
|
|
267035
|
+
process.exit(0);
|
|
267036
|
+
} catch (error2) {
|
|
267037
|
+
const errorMessage = formatErrorMessage(error2);
|
|
267038
|
+
const jsonOutput = getJsonFlag(cmd);
|
|
267039
|
+
if (jsonOutput) {
|
|
267040
|
+
console.error(JSON.stringify({ error: errorMessage }));
|
|
267041
|
+
process.exit(1);
|
|
267042
|
+
}
|
|
266835
267043
|
console.error(source_default.red(`
|
|
266836
267044
|
✗ Error: ${errorMessage}
|
|
266837
267045
|
`));
|
|
@@ -266839,336 +267047,143 @@ function attachBulletinCommands(root) {
|
|
|
266839
267047
|
}
|
|
266840
267048
|
}
|
|
266841
267049
|
});
|
|
266842
|
-
const
|
|
266843
|
-
|
|
267050
|
+
const ownerOfCommand = lookupCommand.command("owner-of <label>").description("Show whether a name is registered and who owns it").alias("oo").option("--json", "Output result as JSON (suppresses all other output)", false);
|
|
267051
|
+
addAuthOptions(ownerOfCommand).action(async (label, options2, cmd) => {
|
|
266844
267052
|
try {
|
|
266845
|
-
const
|
|
266846
|
-
const
|
|
266847
|
-
|
|
266848
|
-
|
|
266849
|
-
|
|
266850
|
-
|
|
266851
|
-
if (history.length === 0) {
|
|
266852
|
-
console.log(source_default.yellow(`
|
|
266853
|
-
No uploads in history.
|
|
266854
|
-
`));
|
|
266855
|
-
console.log(source_default.gray(` Upload files with: dotns bulletin upload <path>
|
|
266856
|
-
`));
|
|
266857
|
-
process.exit(0);
|
|
266858
|
-
}
|
|
266859
|
-
console.log(source_default.blue(`
|
|
266860
|
-
▶ Upload History
|
|
266861
|
-
`));
|
|
266862
|
-
console.log(source_default.gray(` ${history.length} upload(s) found
|
|
267053
|
+
const merged = { ...options2 ?? {}, ...getAuthOptions(cmd) };
|
|
267054
|
+
const jsonOutput = getJsonFlag(cmd);
|
|
267055
|
+
const { clientWrapper, account } = await maybeQuiet(jsonOutput, () => prepareReadOnlyContext(merged));
|
|
267056
|
+
if (!jsonOutput)
|
|
267057
|
+
console.log(source_default.bold(`
|
|
267058
|
+
▶ Ownership Lookup
|
|
266863
267059
|
`));
|
|
266864
|
-
|
|
266865
|
-
const num = (index + 1).toString().padStart(2, " ");
|
|
266866
|
-
console.log(source_default.yellow(` ${num}.`) + source_default.white(` ${formatRecordTimestamp(record2)}`));
|
|
266867
|
-
console.log(source_default.gray(" cid: ") + source_default.cyan(record2.cid));
|
|
266868
|
-
console.log(source_default.gray(" path: ") + source_default.white(record2.path));
|
|
266869
|
-
console.log(source_default.gray(" type: ") + source_default.white(record2.type));
|
|
266870
|
-
if (record2.size > 0) {
|
|
266871
|
-
console.log(source_default.gray(" size: ") + source_default.white(formatBytes(record2.size)));
|
|
266872
|
-
}
|
|
266873
|
-
console.log(source_default.gray(" preview: ") + source_default.blue(getPreviewUrl(record2)));
|
|
266874
|
-
console.log();
|
|
266875
|
-
});
|
|
266876
|
-
process.exit(0);
|
|
266877
|
-
} catch (error2) {
|
|
266878
|
-
const jsonOutput = getJsonFlag(command);
|
|
267060
|
+
const result = await maybeQuiet(jsonOutput, () => performOwnerOfLookup(label, account.address, clientWrapper));
|
|
266879
267061
|
if (jsonOutput) {
|
|
266880
|
-
|
|
266881
|
-
}
|
|
266882
|
-
console.error(source_default.red(`
|
|
266883
|
-
✗ Error: ${formatErrorMessage(error2)}
|
|
266884
|
-
`));
|
|
266885
|
-
process.exit(1);
|
|
266886
|
-
}
|
|
266887
|
-
});
|
|
266888
|
-
bulletinCommand.command("history:remove <cid>").description("Remove an upload from history by CID").action(async (cid) => {
|
|
266889
|
-
try {
|
|
266890
|
-
const removed = await removeUploadRecord(cid);
|
|
266891
|
-
if (removed) {
|
|
266892
|
-
console.log(source_default.green(`
|
|
266893
|
-
✓ Removed ${cid} from history
|
|
266894
|
-
`));
|
|
267062
|
+
console.log(JSON.stringify(result));
|
|
266895
267063
|
} else {
|
|
266896
|
-
console.log(source_default.
|
|
266897
|
-
|
|
267064
|
+
console.log(source_default.green(`
|
|
267065
|
+
✓ Complete
|
|
266898
267066
|
`));
|
|
266899
267067
|
}
|
|
266900
267068
|
process.exit(0);
|
|
266901
267069
|
} catch (error2) {
|
|
267070
|
+
const errorMessage = formatErrorMessage(error2);
|
|
267071
|
+
const jsonOutput = getJsonFlag(cmd);
|
|
267072
|
+
if (jsonOutput) {
|
|
267073
|
+
console.error(JSON.stringify({ error: errorMessage }));
|
|
267074
|
+
process.exit(1);
|
|
267075
|
+
}
|
|
266902
267076
|
console.error(source_default.red(`
|
|
266903
|
-
✗ Error: ${
|
|
266904
|
-
`));
|
|
266905
|
-
process.exit(1);
|
|
266906
|
-
}
|
|
266907
|
-
});
|
|
266908
|
-
addReporterOption(bulletinCommand.command("history:clear").description("Clear all upload history")).action(async () => {
|
|
266909
|
-
try {
|
|
266910
|
-
const count2 = await clearHistory();
|
|
266911
|
-
const historyPath = getHistoryPath();
|
|
266912
|
-
console.log(source_default.green(`
|
|
266913
|
-
✓ Cleared ${count2} upload(s) from history`));
|
|
266914
|
-
console.log(source_default.gray(` ${historyPath}
|
|
266915
|
-
`));
|
|
266916
|
-
process.exit(0);
|
|
266917
|
-
} catch (error2) {
|
|
266918
|
-
console.error(source_default.red(`
|
|
266919
|
-
✗ Error: ${formatErrorMessage(error2)}
|
|
267077
|
+
✗ Error: ${errorMessage}
|
|
266920
267078
|
`));
|
|
266921
267079
|
process.exit(1);
|
|
266922
267080
|
}
|
|
266923
267081
|
});
|
|
266924
|
-
|
|
266925
|
-
|
|
266926
|
-
const jsonOutput = getJsonFlag(command) || Boolean(options2.json);
|
|
266927
|
-
const reporter = createCliReporter(mergedOptions.reporter);
|
|
266928
|
-
const p2pTask = reporter.task("Connecting to Bulletin P2P");
|
|
267082
|
+
const transferCommand = lookupCommand.command("transfer [label]").description("Transfer domain ownership to another address or label").requiredOption("-d, --destination <destination>", "Transfer destination (EVM address, SS58 address, or domain label)").option("--json", "Output result as JSON (suppresses all other output)", false);
|
|
267083
|
+
addAuthOptions(transferCommand).action(async (positionalLabel, options2, cmd) => {
|
|
266929
267084
|
try {
|
|
266930
|
-
|
|
266931
|
-
|
|
266932
|
-
|
|
266933
|
-
|
|
267085
|
+
const merged = { ...options2 ?? {}, ...getAuthOptions(cmd) };
|
|
267086
|
+
const jsonOutput = getJsonFlag(cmd);
|
|
267087
|
+
const label = positionalLabel || merged.name || cmd.parent?.opts()?.name;
|
|
267088
|
+
if (!label) {
|
|
267089
|
+
throw new Error("Domain label is required: dotns lookup transfer <label> -d <destination>");
|
|
266934
267090
|
}
|
|
266935
|
-
const
|
|
266936
|
-
if (
|
|
266937
|
-
|
|
266938
|
-
if (jsonOutput) {
|
|
266939
|
-
writeBulletinJson({
|
|
266940
|
-
cid,
|
|
266941
|
-
resolvable: true,
|
|
266942
|
-
method: "p2p",
|
|
266943
|
-
gateways: [{ gateway: "p2p/bitswap", resolvable: true }]
|
|
266944
|
-
});
|
|
266945
|
-
} else {
|
|
266946
|
-
console.log(source_default.gray(" ✓ ") + source_default.white("p2p/bitswap"));
|
|
266947
|
-
console.log();
|
|
266948
|
-
}
|
|
266949
|
-
cleanupHeliaAndExit(0);
|
|
267091
|
+
const destination = merged.destination;
|
|
267092
|
+
if (!isValidTransferDestination(destination)) {
|
|
267093
|
+
throw new Error("Invalid transfer destination: must be a valid EVM address, Substrate address, or domain label");
|
|
266950
267094
|
}
|
|
266951
|
-
|
|
266952
|
-
const
|
|
266953
|
-
|
|
266954
|
-
|
|
266955
|
-
|
|
266956
|
-
|
|
266957
|
-
|
|
266958
|
-
|
|
266959
|
-
} else {
|
|
266960
|
-
failedGateways.push(gateway);
|
|
266961
|
-
}
|
|
267095
|
+
const context = await maybeQuiet(jsonOutput, () => prepareAssetHubContext(merged));
|
|
267096
|
+
const { clientWrapper, substrateAddress, signer, evmAddress } = context;
|
|
267097
|
+
if (!jsonOutput) {
|
|
267098
|
+
console.log(source_default.bold(`
|
|
267099
|
+
▶ Transfer
|
|
267100
|
+
`));
|
|
267101
|
+
console.log(source_default.gray(" domain: ") + source_default.cyan(`${label}.dot`));
|
|
267102
|
+
console.log(source_default.gray(" to: ") + source_default.white(destination));
|
|
266962
267103
|
}
|
|
267104
|
+
await maybeQuiet(jsonOutput, () => step("Ensuring account mapped", async () => clientWrapper.ensureAccountMapped(substrateAddress, signer)));
|
|
267105
|
+
const recipient = await maybeQuiet(jsonOutput, () => step("Resolving recipient", async () => resolveRecipientByKind(clientWrapper, substrateAddress, destination)));
|
|
267106
|
+
await maybeQuiet(jsonOutput, () => step("Transferring domain", async () => transferDomain(clientWrapper, substrateAddress, signer, evmAddress, recipient, label)));
|
|
267107
|
+
await maybeQuiet(jsonOutput, () => step("Verifying ownership", async () => verifyDomainOwnership(clientWrapper, substrateAddress, label, recipient)));
|
|
266963
267108
|
if (jsonOutput) {
|
|
266964
|
-
|
|
266965
|
-
|
|
266966
|
-
|
|
266967
|
-
|
|
266968
|
-
|
|
267109
|
+
console.log(JSON.stringify({
|
|
267110
|
+
label,
|
|
267111
|
+
domain: `${label}.dot`,
|
|
267112
|
+
destination,
|
|
267113
|
+
recipient,
|
|
267114
|
+
transferred: true
|
|
266969
267115
|
}));
|
|
266970
|
-
writeBulletinJson({
|
|
266971
|
-
cid,
|
|
266972
|
-
resolvable: resolvableGateways.length > 0,
|
|
266973
|
-
method: resolvableGateways.length > 0 ? "gateway" : "none",
|
|
266974
|
-
gateways: entries
|
|
266975
|
-
});
|
|
266976
|
-
cleanupHeliaAndExit(resolvableGateways.length > 0 ? 0 : 1);
|
|
266977
|
-
}
|
|
266978
|
-
if (resolvableGateways.length > 0) {
|
|
266979
|
-
gatewayTask.succeed(`CID resolvable on ${resolvableGateways.length} gateway(s)`);
|
|
266980
|
-
for (const gw of resolvableGateways) {
|
|
266981
|
-
console.log(source_default.gray(" ✓ ") + source_default.white(gw));
|
|
266982
|
-
}
|
|
266983
267116
|
} else {
|
|
266984
|
-
|
|
266985
|
-
|
|
266986
|
-
|
|
266987
|
-
for (const gw of failedGateways) {
|
|
266988
|
-
console.log(source_default.gray(" ✗ ") + source_default.dim(gw));
|
|
266989
|
-
}
|
|
267117
|
+
console.log(source_default.green(`
|
|
267118
|
+
✓ Complete
|
|
267119
|
+
`));
|
|
266990
267120
|
}
|
|
266991
|
-
|
|
266992
|
-
cleanupHeliaAndExit(resolvableGateways.length > 0 ? 0 : 1);
|
|
267121
|
+
process.exit(0);
|
|
266993
267122
|
} catch (error2) {
|
|
266994
|
-
p2pTask.fail("Verification failed");
|
|
266995
267123
|
const errorMessage = formatErrorMessage(error2);
|
|
267124
|
+
const jsonOutput = getJsonFlag(cmd);
|
|
266996
267125
|
if (jsonOutput) {
|
|
266997
|
-
|
|
266998
|
-
|
|
266999
|
-
|
|
267126
|
+
console.error(JSON.stringify({ error: errorMessage }));
|
|
267127
|
+
process.exit(1);
|
|
267128
|
+
}
|
|
267129
|
+
console.error(source_default.red(`
|
|
267000
267130
|
✗ Error: ${errorMessage}
|
|
267001
267131
|
`));
|
|
267002
|
-
|
|
267003
|
-
}
|
|
267132
|
+
process.exit(1);
|
|
267004
267133
|
}
|
|
267005
267134
|
});
|
|
267006
267135
|
}
|
|
267007
267136
|
|
|
267008
267137
|
// src/cli/commands/content.ts
|
|
267009
|
-
init_source();
|
|
267010
|
-
|
|
267011
|
-
// src/commands/contentHash.ts
|
|
267012
|
-
init_source();
|
|
267013
|
-
init__esm();
|
|
267014
|
-
init_constants();
|
|
267015
|
-
init_contractInteractions();
|
|
267016
|
-
|
|
267017
|
-
// src/commands/resolverAuth.ts
|
|
267018
|
-
init__esm();
|
|
267019
|
-
init_constants();
|
|
267020
|
-
init_contractInteractions();
|
|
267021
|
-
async function getResolverNodeInfo(clientWrapper, originSubstrateAddress, namehashNode) {
|
|
267022
|
-
const exists2 = await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRY, DOTNS_REGISTRY_ABI, "recordExists", [namehashNode]);
|
|
267023
|
-
const owner = await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRY, DOTNS_REGISTRY_ABI, "owner", [namehashNode]);
|
|
267024
|
-
const caller = await clientWrapper.getEvmAddress(originSubstrateAddress);
|
|
267025
|
-
return { exists: exists2 && owner !== zeroAddress, owner, caller };
|
|
267026
|
-
}
|
|
267027
|
-
async function requireResolverAuthorization(clientWrapper, originSubstrateAddress, owner, caller) {
|
|
267028
|
-
const isOwner = checksumAddress(owner) === checksumAddress(caller);
|
|
267029
|
-
const isApproved = await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_CONTENT_RESOLVER, DOTNS_CONTENT_RESOLVER_ABI, "isApprovedForAll", [owner, caller]);
|
|
267030
|
-
if (!isOwner && !isApproved) {
|
|
267031
|
-
throw new Error(`You do not own this domain. Owner is ${owner}, but you are ${caller}`);
|
|
267032
|
-
}
|
|
267033
|
-
}
|
|
267034
|
-
|
|
267035
|
-
// src/commands/contentHash.ts
|
|
267036
|
-
function decodeContenthashToCid(contenthash) {
|
|
267037
|
-
if (contenthash === "0x" || contenthash === "0x0" || contenthash.length < 6) {
|
|
267038
|
-
return "No CID set";
|
|
267039
|
-
}
|
|
267040
|
-
const cid = decodeIpfsContenthash(contenthash);
|
|
267041
|
-
return cid ?? `Unable to decode: ${contenthash}`;
|
|
267042
|
-
}
|
|
267043
|
-
function encodeCidToContenthash(cidString) {
|
|
267044
|
-
const encoded = encodeIpfsContenthash(cidString);
|
|
267045
|
-
return `0x${encoded}`;
|
|
267046
|
-
}
|
|
267047
|
-
async function viewDomainContentHash(clientWrapper, originSubstrateAddress, label, spinner) {
|
|
267048
|
-
const namehashNode = namehash(`${label}.dot`);
|
|
267049
|
-
spinner.start("Querying registry");
|
|
267050
|
-
const recordExists = await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRY, DOTNS_REGISTRY_ABI, "recordExists", [namehashNode]);
|
|
267051
|
-
const ownerAddress = await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_REGISTRY, DOTNS_REGISTRY_ABI, "owner", [namehashNode]);
|
|
267052
|
-
spinner.succeed("Registry read");
|
|
267053
|
-
console.log(source_default.gray(" registry: ") + source_default.white(CONTRACTS.DOTNS_REGISTRY));
|
|
267054
|
-
console.log(source_default.gray(" domain: ") + source_default.cyan(`${label}.dot`));
|
|
267055
|
-
console.log(source_default.gray(" node: ") + source_default.white(namehashNode));
|
|
267056
|
-
console.log(source_default.gray(" exists: ") + source_default.white(String(recordExists)));
|
|
267057
|
-
console.log(source_default.gray(" owner: ") + source_default.white(ownerAddress));
|
|
267058
|
-
console.log();
|
|
267059
|
-
if (!recordExists || ownerAddress === zeroAddress) {
|
|
267060
|
-
console.log(source_default.yellow(" status: Domain not registered"));
|
|
267061
|
-
return;
|
|
267062
|
-
}
|
|
267063
|
-
const contentHashBytes = await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_CONTENT_RESOLVER, DOTNS_CONTENT_RESOLVER_ABI, "contenthash", [namehashNode]);
|
|
267064
|
-
const decodedCid = decodeContenthashToCid(contentHashBytes);
|
|
267065
|
-
console.log(source_default.gray(" resolver: ") + source_default.white(CONTRACTS.DOTNS_CONTENT_RESOLVER));
|
|
267066
|
-
console.log(source_default.gray(" contenthash: ") + source_default.white(contentHashBytes));
|
|
267067
|
-
console.log(source_default.gray(" cid: ") + source_default.cyan(decodedCid));
|
|
267068
|
-
}
|
|
267069
|
-
async function setDomainContentHash(clientWrapper, originSubstrateAddress, signer, label, contentId, spinner) {
|
|
267070
|
-
const namehashNode = namehash(`${label}.dot`);
|
|
267071
|
-
console.log(source_default.gray(" domain: ") + source_default.cyan(`${label}.dot`));
|
|
267072
|
-
console.log(source_default.gray(" node: ") + source_default.white(namehashNode));
|
|
267073
|
-
console.log();
|
|
267074
|
-
const { exists: exists2, owner, caller } = await getResolverNodeInfo(clientWrapper, originSubstrateAddress, namehashNode);
|
|
267075
|
-
console.log(source_default.gray(" exists: ") + source_default.white(String(exists2)));
|
|
267076
|
-
console.log(source_default.gray(" owner: ") + source_default.white(owner));
|
|
267077
|
-
console.log(source_default.gray(" caller: ") + source_default.white(caller));
|
|
267078
|
-
console.log();
|
|
267079
|
-
if (!exists2) {
|
|
267080
|
-
throw new Error(`Domain ${label}.dot is not registered`);
|
|
267081
|
-
}
|
|
267082
|
-
await requireResolverAuthorization(clientWrapper, originSubstrateAddress, owner, caller);
|
|
267083
|
-
console.log(source_default.gray(" status: ") + source_default.green("Ownership verified"));
|
|
267084
|
-
console.log();
|
|
267085
|
-
try {
|
|
267086
|
-
const currentContentHash = await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_CONTENT_RESOLVER, DOTNS_CONTENT_RESOLVER_ABI, "contenthash", [namehashNode]);
|
|
267087
|
-
const currentCid = decodeContenthashToCid(currentContentHash);
|
|
267088
|
-
console.log(source_default.gray(" current: ") + source_default.cyan(currentCid));
|
|
267089
|
-
} catch {
|
|
267090
|
-
console.log(source_default.gray(" current: ") + source_default.yellow("Not set or error reading"));
|
|
267091
|
-
}
|
|
267092
|
-
console.log();
|
|
267093
|
-
const contentBytes = encodeCidToContenthash(contentId);
|
|
267094
|
-
console.log(source_default.gray(" resolver: ") + source_default.white(CONTRACTS.DOTNS_CONTENT_RESOLVER));
|
|
267095
|
-
console.log(source_default.gray(" node: ") + source_default.white(namehashNode));
|
|
267096
|
-
console.log(source_default.gray(" cid: ") + source_default.cyan(contentId));
|
|
267097
|
-
console.log(source_default.gray(" bytes: ") + source_default.white(contentBytes));
|
|
267098
|
-
spinner.start("Submitting setContenthash");
|
|
267099
|
-
const transactionHash = await submitContractTransaction(clientWrapper, CONTRACTS.DOTNS_CONTENT_RESOLVER, 0n, DOTNS_CONTENT_RESOLVER_ABI, "setContenthash", [namehashNode, contentBytes], originSubstrateAddress, signer, spinner, "setContenthash");
|
|
267100
|
-
console.log(source_default.gray(" tx: ") + source_default.blue(transactionHash));
|
|
267101
|
-
const updatedContentHash = await performContractCall(clientWrapper, originSubstrateAddress, CONTRACTS.DOTNS_CONTENT_RESOLVER, DOTNS_CONTENT_RESOLVER_ABI, "contenthash", [namehashNode]);
|
|
267102
|
-
const updatedCid = decodeContenthashToCid(updatedContentHash);
|
|
267103
|
-
console.log();
|
|
267104
|
-
console.log(source_default.gray(" new: ") + source_default.cyan(updatedCid));
|
|
267105
|
-
}
|
|
267106
|
-
|
|
267107
|
-
// src/cli/commands/content.ts
|
|
267108
|
-
init_formatting();
|
|
267109
267138
|
init_ora();
|
|
267110
|
-
function getMergedOptions3(command, fallback) {
|
|
267111
|
-
const mergedOptions = { ...fallback ?? {} };
|
|
267112
|
-
let currentCommand = command?.parent;
|
|
267113
|
-
while (currentCommand) {
|
|
267114
|
-
if (typeof currentCommand.opts === "function") {
|
|
267115
|
-
const parentOptions = currentCommand.opts();
|
|
267116
|
-
for (const key in parentOptions) {
|
|
267117
|
-
if (!(key in mergedOptions) && parentOptions[key] !== undefined) {
|
|
267118
|
-
mergedOptions[key] = parentOptions[key];
|
|
267119
|
-
}
|
|
267120
|
-
}
|
|
267121
|
-
}
|
|
267122
|
-
currentCommand = currentCommand.parent;
|
|
267123
|
-
}
|
|
267124
|
-
return mergedOptions;
|
|
267125
|
-
}
|
|
267126
267139
|
function attachContentCommands(root) {
|
|
267127
267140
|
const contentCommand = root.command("content").description("Manage domain content hashes");
|
|
267128
267141
|
addAuthOptions(contentCommand);
|
|
267129
|
-
const viewContentCommand = contentCommand.command("view <name>").description("View domain content hash");
|
|
267142
|
+
const viewContentCommand = contentCommand.command("view <name>").description("View domain content hash").option("--json", "Output result as JSON (suppresses all other output)", false);
|
|
267130
267143
|
addAuthOptions(viewContentCommand).action(async (name10, options2, command) => {
|
|
267144
|
+
const jsonOutput = getJsonFlag(command);
|
|
267131
267145
|
try {
|
|
267132
|
-
const mergedOptions =
|
|
267133
|
-
const context = await prepareReadOnlyContext(mergedOptions);
|
|
267134
|
-
|
|
267146
|
+
const mergedOptions = getMergedOptions(command, options2);
|
|
267147
|
+
const context = await maybeQuiet(jsonOutput, () => prepareReadOnlyContext(mergedOptions));
|
|
267148
|
+
if (!jsonOutput)
|
|
267149
|
+
console.log(source_default.bold(`
|
|
267135
267150
|
▶ Content View
|
|
267136
267151
|
`));
|
|
267137
267152
|
const spinner = ora();
|
|
267138
|
-
await viewDomainContentHash(context.clientWrapper, context.account.address, name10, spinner);
|
|
267139
|
-
|
|
267153
|
+
const result = await maybeQuiet(jsonOutput, () => viewDomainContentHash(context.clientWrapper, context.account.address, name10, spinner));
|
|
267154
|
+
if (!emitJsonResult(jsonOutput, result)) {
|
|
267155
|
+
console.log(source_default.green(`
|
|
267140
267156
|
✓ Complete
|
|
267141
267157
|
`));
|
|
267158
|
+
}
|
|
267142
267159
|
process.exit(0);
|
|
267143
267160
|
} catch (error2) {
|
|
267144
|
-
|
|
267145
|
-
✗ Error: ${formatErrorMessage(error2)}
|
|
267146
|
-
`));
|
|
267147
|
-
process.exit(1);
|
|
267161
|
+
handleCommandError(jsonOutput, error2);
|
|
267148
267162
|
}
|
|
267149
267163
|
});
|
|
267150
|
-
const setContentCommand = contentCommand.command("set <name> <cid>").description("Set domain content hash (IPFS CID)");
|
|
267164
|
+
const setContentCommand = contentCommand.command("set <name> <cid>").description("Set domain content hash (IPFS CID)").option("--json", "Output result as JSON (suppresses all other output)", false);
|
|
267151
267165
|
addAuthOptions(setContentCommand).action(async (name10, cid, options2, command) => {
|
|
267166
|
+
const jsonOutput = getJsonFlag(command);
|
|
267152
267167
|
try {
|
|
267153
|
-
const mergedOptions =
|
|
267168
|
+
const mergedOptions = getMergedOptions(command, options2);
|
|
267154
267169
|
if (mergedOptions.mnemonic && mergedOptions.keyUri) {
|
|
267155
267170
|
throw new Error("Cannot specify both --mnemonic and --key-uri");
|
|
267156
267171
|
}
|
|
267157
|
-
const context = await prepareContext({ ...mergedOptions, useRevive: true });
|
|
267158
|
-
|
|
267172
|
+
const context = await maybeQuiet(jsonOutput, () => prepareContext({ ...mergedOptions, useRevive: true }));
|
|
267173
|
+
if (!jsonOutput)
|
|
267174
|
+
console.log(source_default.bold(`
|
|
267159
267175
|
▶ Content Set
|
|
267160
267176
|
`));
|
|
267161
267177
|
const spinner = ora();
|
|
267162
|
-
await setDomainContentHash(context.clientWrapper, context.substrateAddress, context.signer, name10, cid, spinner);
|
|
267163
|
-
|
|
267178
|
+
const result = await maybeQuiet(jsonOutput, () => setDomainContentHash(context.clientWrapper, context.substrateAddress, context.signer, name10, cid, spinner));
|
|
267179
|
+
if (!emitJsonResult(jsonOutput, result)) {
|
|
267180
|
+
console.log(source_default.green(`
|
|
267164
267181
|
✓ Complete
|
|
267165
267182
|
`));
|
|
267183
|
+
}
|
|
267166
267184
|
process.exit(0);
|
|
267167
267185
|
} catch (error2) {
|
|
267168
|
-
|
|
267169
|
-
✗ Error: ${formatErrorMessage(error2)}
|
|
267170
|
-
`));
|
|
267171
|
-
process.exit(1);
|
|
267186
|
+
handleCommandError(jsonOutput, error2);
|
|
267172
267187
|
}
|
|
267173
267188
|
});
|
|
267174
267189
|
}
|
|
@@ -267241,22 +267256,6 @@ async function setDomainText(clientWrapper, originSubstrateAddress, signer, labe
|
|
|
267241
267256
|
// src/cli/commands/text.ts
|
|
267242
267257
|
init_formatting();
|
|
267243
267258
|
init_ora();
|
|
267244
|
-
function getMergedOptions4(command, fallback) {
|
|
267245
|
-
const mergedOptions = { ...fallback ?? {} };
|
|
267246
|
-
let currentCommand = command?.parent;
|
|
267247
|
-
while (currentCommand) {
|
|
267248
|
-
if (typeof currentCommand.opts === "function") {
|
|
267249
|
-
const parentOptions = currentCommand.opts();
|
|
267250
|
-
for (const key in parentOptions) {
|
|
267251
|
-
if (!(key in mergedOptions) && parentOptions[key] !== undefined) {
|
|
267252
|
-
mergedOptions[key] = parentOptions[key];
|
|
267253
|
-
}
|
|
267254
|
-
}
|
|
267255
|
-
}
|
|
267256
|
-
currentCommand = currentCommand.parent;
|
|
267257
|
-
}
|
|
267258
|
-
return mergedOptions;
|
|
267259
|
-
}
|
|
267260
267259
|
function attachTextCommands(root) {
|
|
267261
267260
|
const textCommand = root.command("text").description("Manage domain text records");
|
|
267262
267261
|
addAuthOptions(textCommand);
|
|
@@ -267269,7 +267268,7 @@ function attachTextCommands(root) {
|
|
|
267269
267268
|
process.stdout.write = process.stderr.write.bind(process.stderr);
|
|
267270
267269
|
}
|
|
267271
267270
|
try {
|
|
267272
|
-
const mergedOptions =
|
|
267271
|
+
const mergedOptions = getMergedOptions(command, options2);
|
|
267273
267272
|
const context = await prepareReadOnlyContext(mergedOptions);
|
|
267274
267273
|
console.error(source_default.bold(`
|
|
267275
267274
|
▶ Text View
|
|
@@ -267293,7 +267292,7 @@ function attachTextCommands(root) {
|
|
|
267293
267292
|
const setTextCommand = textCommand.command("set <name> <key> [value]").description("Set a domain text record (reads from stdin if value omitted)");
|
|
267294
267293
|
addAuthOptions(setTextCommand).action(async (name10, key, value3, options2, command) => {
|
|
267295
267294
|
try {
|
|
267296
|
-
const mergedOptions =
|
|
267295
|
+
const mergedOptions = getMergedOptions(command, options2);
|
|
267297
267296
|
if (!value3) {
|
|
267298
267297
|
if (process.stdin.isTTY) {
|
|
267299
267298
|
throw new Error("No value provided. Pass a value argument or pipe via stdin.");
|
|
@@ -267328,24 +267327,6 @@ function attachTextCommands(root) {
|
|
|
267328
267327
|
|
|
267329
267328
|
// src/cli/commands/pop.ts
|
|
267330
267329
|
init_source();
|
|
267331
|
-
init_formatting();
|
|
267332
|
-
function getMergedOptions5(command, fallback) {
|
|
267333
|
-
const mergedOptions = { ...fallback ?? {} };
|
|
267334
|
-
let currentCommand = command?.parent;
|
|
267335
|
-
while (currentCommand) {
|
|
267336
|
-
if (typeof currentCommand.opts === "function") {
|
|
267337
|
-
const parentOptions = currentCommand.opts();
|
|
267338
|
-
for (const key in parentOptions) {
|
|
267339
|
-
const optionKey = key;
|
|
267340
|
-
if (!(optionKey in mergedOptions) && parentOptions[optionKey] !== undefined) {
|
|
267341
|
-
mergedOptions[optionKey] = parentOptions[optionKey];
|
|
267342
|
-
}
|
|
267343
|
-
}
|
|
267344
|
-
}
|
|
267345
|
-
currentCommand = currentCommand.parent;
|
|
267346
|
-
}
|
|
267347
|
-
return mergedOptions;
|
|
267348
|
-
}
|
|
267349
267330
|
async function readPopInfo(options2) {
|
|
267350
267331
|
const context = await prepareReadOnlyContext(options2);
|
|
267351
267332
|
const status = await getUserProofOfPersonhoodStatus(context.clientWrapper, context.account.address, context.evmAddress);
|
|
@@ -267358,51 +267339,58 @@ async function readPopInfo(options2) {
|
|
|
267358
267339
|
function attachPopCommands(root) {
|
|
267359
267340
|
const popCommand = root.command("pop").description("ProofOfPersonhood status management");
|
|
267360
267341
|
addAuthOptions(popCommand);
|
|
267361
|
-
const setPopCommand = popCommand.command("set <status>").description("Set ProofOfPersonhood status (none, lite, or full)");
|
|
267342
|
+
const setPopCommand = popCommand.command("set <status>").description("Set ProofOfPersonhood status (none, lite, or full)").option("--json", "Output result as JSON (suppresses all other output)", false);
|
|
267362
267343
|
addAuthOptions(setPopCommand).action(async (status, options2, command) => {
|
|
267344
|
+
const jsonOutput = getJsonFlag(command);
|
|
267363
267345
|
try {
|
|
267364
|
-
const mergedOptions =
|
|
267365
|
-
const context = await prepareContext(mergedOptions);
|
|
267346
|
+
const mergedOptions = getMergedOptions(command, options2);
|
|
267347
|
+
const context = await maybeQuiet(jsonOutput, () => prepareContext(mergedOptions));
|
|
267366
267348
|
const parsedStatus = parseProofOfPersonhoodStatus(status);
|
|
267367
|
-
await setUserProofOfPersonhoodStatus(context.clientWrapper, context.substrateAddress, context.signer, context.evmAddress, "", parsedStatus);
|
|
267368
|
-
|
|
267349
|
+
await maybeQuiet(jsonOutput, () => setUserProofOfPersonhoodStatus(context.clientWrapper, context.substrateAddress, context.signer, context.evmAddress, "", parsedStatus));
|
|
267350
|
+
if (!emitJsonResult(jsonOutput, {
|
|
267351
|
+
ok: true,
|
|
267352
|
+
status: ProofOfPersonhoodStatus[parsedStatus].toLowerCase(),
|
|
267353
|
+
statusCode: parsedStatus
|
|
267354
|
+
})) {
|
|
267355
|
+
console.log(source_default.green(`
|
|
267369
267356
|
✓ PoP Status Updated
|
|
267370
267357
|
`));
|
|
267358
|
+
}
|
|
267371
267359
|
process.exit(0);
|
|
267372
267360
|
} catch (error2) {
|
|
267373
|
-
|
|
267374
|
-
✗ Error: ${formatErrorMessage(error2)}
|
|
267375
|
-
`));
|
|
267376
|
-
process.exit(1);
|
|
267361
|
+
handleCommandError(jsonOutput, error2);
|
|
267377
267362
|
}
|
|
267378
267363
|
});
|
|
267379
|
-
const infoCommand = popCommand.command("info").description("Display ProofOfPersonhood status");
|
|
267364
|
+
const infoCommand = popCommand.command("info").description("Display ProofOfPersonhood status").option("--json", "Output result as JSON (suppresses all other output)", false);
|
|
267380
267365
|
addAuthOptions(infoCommand).action(async (options2, command) => {
|
|
267366
|
+
const jsonOutput = getJsonFlag(command);
|
|
267381
267367
|
try {
|
|
267382
|
-
const mergedOptions =
|
|
267383
|
-
const info2 = await readPopInfo(mergedOptions);
|
|
267384
|
-
|
|
267368
|
+
const mergedOptions = getMergedOptions(command, options2);
|
|
267369
|
+
const info2 = await maybeQuiet(jsonOutput, () => readPopInfo(mergedOptions));
|
|
267370
|
+
if (!emitJsonResult(jsonOutput, {
|
|
267371
|
+
substrate: info2.substrate,
|
|
267372
|
+
evm: info2.evm,
|
|
267373
|
+
status: ProofOfPersonhoodStatus[info2.status].toLowerCase(),
|
|
267374
|
+
statusCode: info2.status
|
|
267375
|
+
})) {
|
|
267376
|
+
console.log(source_default.bold(`
|
|
267385
267377
|
\uD83D\uDCCB ProofOfPersonhood Status
|
|
267386
267378
|
`));
|
|
267387
|
-
|
|
267388
|
-
|
|
267389
|
-
|
|
267390
|
-
|
|
267379
|
+
console.log(source_default.gray(" substrate: ") + source_default.white(info2.substrate));
|
|
267380
|
+
console.log(source_default.gray(" evm: ") + source_default.white(info2.evm));
|
|
267381
|
+
console.log(source_default.gray(" status: ") + source_default.white(ProofOfPersonhoodStatus[info2.status]));
|
|
267382
|
+
console.log(source_default.green(`
|
|
267391
267383
|
✓ PoP Status Retrieved
|
|
267392
267384
|
`));
|
|
267385
|
+
}
|
|
267393
267386
|
process.exit(0);
|
|
267394
267387
|
} catch (error2) {
|
|
267395
|
-
|
|
267396
|
-
✗ Error: ${formatErrorMessage(error2)}
|
|
267397
|
-
`));
|
|
267398
|
-
process.exit(1);
|
|
267388
|
+
handleCommandError(jsonOutput, error2);
|
|
267399
267389
|
}
|
|
267400
267390
|
});
|
|
267401
267391
|
}
|
|
267402
267392
|
|
|
267403
267393
|
// src/cli/commands/registerCommand.ts
|
|
267404
|
-
init_source();
|
|
267405
|
-
init_formatting();
|
|
267406
267394
|
init_constants();
|
|
267407
267395
|
function resolveCommitmentBuffer(cliValue) {
|
|
267408
267396
|
const raw = cliValue ?? process.env.DOTNS_COMMITMENT_BUFFER;
|
|
@@ -267416,7 +267404,8 @@ function resolveCommitmentBuffer(cliValue) {
|
|
|
267416
267404
|
}
|
|
267417
267405
|
function attachRegisterCommand(root) {
|
|
267418
267406
|
const registerCommand = root.command("register").description("Domain registration commands");
|
|
267419
|
-
const domainCommand = registerCommand.command("domain").description("Register a new base domain").option("-n, --name <label>", "Domain label to register (without .dot)").option("-s, --status <level>", "ProofOfPersonhood status: none, lite, or full").option("-r, --reverse", "Enable reverse record registration", false).option("-g, --governance", "Use governance registration path", false).option("-o, --owner <address>", "Owner address (EVM or Substrate, or label)").option("--transfer", "Transfer domain after registration", false).option("--to <destination>", "Transfer destination (EVM address, SS58, or domain label)").option("--cb, --commitment-buffer <seconds>", `Extra seconds to wait after minCommitmentAge (default: ${DEFAULT_COMMITMENT_BUFFER_SECONDS}, env: DOTNS_COMMITMENT_BUFFER)`).action(async (options2, cmd) => {
|
|
267407
|
+
const domainCommand = registerCommand.command("domain").description("Register a new base domain").option("-n, --name <label>", "Domain label to register (without .dot)").option("-s, --status <level>", "ProofOfPersonhood status: none, lite, or full").option("-r, --reverse", "Enable reverse record registration", false).option("-g, --governance", "Use governance registration path", false).option("-o, --owner <address>", "Owner address (EVM or Substrate, or label)").option("--transfer", "Transfer domain after registration", false).option("--to <destination>", "Transfer destination (EVM address, SS58, or domain label)").option("--cb, --commitment-buffer <seconds>", `Extra seconds to wait after minCommitmentAge (default: ${DEFAULT_COMMITMENT_BUFFER_SECONDS}, env: DOTNS_COMMITMENT_BUFFER)`).option("--json", "Output result as JSON (suppresses all other output)", false).action(async (options2, cmd) => {
|
|
267408
|
+
const jsonOutput = getJsonFlag(cmd);
|
|
267420
267409
|
try {
|
|
267421
267410
|
const merged = { ...options2, ...getAuthOptions(cmd) };
|
|
267422
267411
|
const allOpts = typeof cmd.optsWithGlobals === "function" ? cmd.optsWithGlobals() : cmd.opts();
|
|
@@ -267425,26 +267414,23 @@ function attachRegisterCommand(root) {
|
|
|
267425
267414
|
if (merged.transfer === true && !merged.to) {
|
|
267426
267415
|
throw new Error("Missing transfer destination: use --to <evm|ss58|label>");
|
|
267427
267416
|
}
|
|
267428
|
-
await executeRegistration(merged);
|
|
267417
|
+
const result = await maybeQuiet(jsonOutput, () => executeRegistration(merged));
|
|
267418
|
+
emitJsonResult(jsonOutput, result);
|
|
267429
267419
|
process.exit(0);
|
|
267430
267420
|
} catch (error2) {
|
|
267431
|
-
|
|
267432
|
-
${source_default.red.bold("✗ Error:")} ${formatErrorMessage(error2)}
|
|
267433
|
-
`);
|
|
267434
|
-
process.exit(1);
|
|
267421
|
+
handleCommandError(jsonOutput, error2);
|
|
267435
267422
|
}
|
|
267436
267423
|
});
|
|
267437
267424
|
addAuthOptions(domainCommand);
|
|
267438
|
-
const subnameCommand = registerCommand.command("subname").description("Register a subname under an existing domain").requiredOption("-n, --name <label>", "Subname label to register").requiredOption("-p, --parent <label>", "Parent domain label (without .dot)").option("-o, --owner <address>", "Owner address (EVM or Substrate, or label)").action(async (options2, cmd) => {
|
|
267425
|
+
const subnameCommand = registerCommand.command("subname").description("Register a subname under an existing domain").requiredOption("-n, --name <label>", "Subname label to register").requiredOption("-p, --parent <label>", "Parent domain label (without .dot)").option("-o, --owner <address>", "Owner address (EVM or Substrate, or label)").option("--json", "Output result as JSON (suppresses all other output)", false).action(async (options2, cmd) => {
|
|
267426
|
+
const jsonOutput = getJsonFlag(cmd);
|
|
267439
267427
|
try {
|
|
267440
267428
|
const merged = { ...options2, ...getAuthOptions(cmd) };
|
|
267441
|
-
await executeSubnameRegistration(merged);
|
|
267429
|
+
const result = await maybeQuiet(jsonOutput, () => executeSubnameRegistration(merged));
|
|
267430
|
+
emitJsonResult(jsonOutput, result);
|
|
267442
267431
|
process.exit(0);
|
|
267443
267432
|
} catch (error2) {
|
|
267444
|
-
|
|
267445
|
-
${source_default.red.bold("✗ Error:")} ${formatErrorMessage(error2)}
|
|
267446
|
-
`);
|
|
267447
|
-
process.exit(1);
|
|
267433
|
+
handleCommandError(jsonOutput, error2);
|
|
267448
267434
|
}
|
|
267449
267435
|
});
|
|
267450
267436
|
addAuthOptions(subnameCommand);
|
|
@@ -267516,29 +267502,13 @@ async function whitelistAddress(clientWrapper, originAddress, signer, targetAddr
|
|
|
267516
267502
|
}
|
|
267517
267503
|
|
|
267518
267504
|
// src/cli/commands/info.ts
|
|
267519
|
-
function getMergedOptions6(command, fallback) {
|
|
267520
|
-
const mergedOptions = { ...fallback ?? {} };
|
|
267521
|
-
let currentCommand = command?.parent;
|
|
267522
|
-
while (currentCommand) {
|
|
267523
|
-
if (typeof currentCommand.opts === "function") {
|
|
267524
|
-
const parentOptions = currentCommand.opts();
|
|
267525
|
-
for (const key in parentOptions) {
|
|
267526
|
-
if (!(key in mergedOptions) && parentOptions[key] !== undefined) {
|
|
267527
|
-
mergedOptions[key] = parentOptions[key];
|
|
267528
|
-
}
|
|
267529
|
-
}
|
|
267530
|
-
}
|
|
267531
|
-
currentCommand = currentCommand.parent;
|
|
267532
|
-
}
|
|
267533
|
-
return mergedOptions;
|
|
267534
|
-
}
|
|
267535
267505
|
function attachAccountCommands(root) {
|
|
267536
267506
|
const accountCommand = root.command("account").description("Account management utilities");
|
|
267537
267507
|
addAuthOptions(accountCommand);
|
|
267538
267508
|
const addressCommand = accountCommand.command("address").description("Print the substrate address for the configured account (offline, no RPC)");
|
|
267539
267509
|
addAuthOptions(addressCommand).action(async (options2, command) => {
|
|
267540
267510
|
try {
|
|
267541
|
-
const mergedOptions =
|
|
267511
|
+
const mergedOptions = getMergedOptions(command, options2);
|
|
267542
267512
|
const keystorePath = resolveKeystorePath(mergedOptions.keystorePath);
|
|
267543
267513
|
const auth = await resolveAuthSource({
|
|
267544
267514
|
mnemonic: mergedOptions.mnemonic,
|
|
@@ -267558,7 +267528,7 @@ function attachAccountCommands(root) {
|
|
|
267558
267528
|
const infoCommand = accountCommand.command("info").description("Display account information including balances");
|
|
267559
267529
|
addAuthOptions(infoCommand).action(async (options2, command) => {
|
|
267560
267530
|
try {
|
|
267561
|
-
const mergedOptions =
|
|
267531
|
+
const mergedOptions = getMergedOptions(command, options2);
|
|
267562
267532
|
const rpc = resolveRpc(mergedOptions.rpc);
|
|
267563
267533
|
const keystorePath = resolveKeystorePath(mergedOptions.keystorePath);
|
|
267564
267534
|
const client = await step(`Connecting RPC ${rpc}`, async () => createClient3(getWsProvider(rpc)).getTypedApi(paseo_default));
|
|
@@ -267590,7 +267560,7 @@ function attachAccountCommands(root) {
|
|
|
267590
267560
|
const mapCommand = accountCommand.command("map").description("Map Substrate account to EVM address");
|
|
267591
267561
|
addAuthOptions(mapCommand).action(async (options2, command) => {
|
|
267592
267562
|
try {
|
|
267593
|
-
const mergedOptions =
|
|
267563
|
+
const mergedOptions = getMergedOptions(command, options2);
|
|
267594
267564
|
const rpc = resolveRpc(mergedOptions.rpc);
|
|
267595
267565
|
const client = await step(`Connecting RPC ${rpc}`, async () => createClient3(getWsProvider(rpc)).getTypedApi(paseo_default));
|
|
267596
267566
|
const clientWrapper = new ReviveClientWrapper(client);
|
|
@@ -267623,7 +267593,7 @@ function attachAccountCommands(root) {
|
|
|
267623
267593
|
addAuthOptions(isMappedCommand).action(async (address, options2, cmd) => {
|
|
267624
267594
|
const jsonOutput = getJsonFlag(cmd);
|
|
267625
267595
|
try {
|
|
267626
|
-
const mergedOptions =
|
|
267596
|
+
const mergedOptions = getMergedOptions(cmd, options2);
|
|
267627
267597
|
const { clientWrapper } = await maybeQuiet(jsonOutput, () => prepareReadOnlyContext(mergedOptions));
|
|
267628
267598
|
const result = await maybeQuiet(jsonOutput, () => checkAccountMapped(clientWrapper, address));
|
|
267629
267599
|
if (jsonOutput)
|
|
@@ -267647,7 +267617,7 @@ function attachAccountCommands(root) {
|
|
|
267647
267617
|
addAuthOptions(isWhitelistedCommand).action(async (address, options2, cmd) => {
|
|
267648
267618
|
const jsonOutput = getJsonFlag(cmd);
|
|
267649
267619
|
try {
|
|
267650
|
-
const mergedOptions =
|
|
267620
|
+
const mergedOptions = getMergedOptions(cmd, options2);
|
|
267651
267621
|
const { clientWrapper, account } = await maybeQuiet(jsonOutput, () => prepareReadOnlyContext(mergedOptions));
|
|
267652
267622
|
const result = await maybeQuiet(jsonOutput, () => checkWhitelisted(clientWrapper, account.address, address));
|
|
267653
267623
|
if (jsonOutput)
|
|
@@ -267671,7 +267641,7 @@ function attachAccountCommands(root) {
|
|
|
267671
267641
|
addAuthOptions(whitelistCommand).action(async (address, options2, cmd) => {
|
|
267672
267642
|
const jsonOutput = getJsonFlag(cmd);
|
|
267673
267643
|
try {
|
|
267674
|
-
const mergedOptions =
|
|
267644
|
+
const mergedOptions = getMergedOptions(cmd, options2);
|
|
267675
267645
|
const enable = !mergedOptions.remove;
|
|
267676
267646
|
const context = await maybeQuiet(jsonOutput, () => prepareAssetHubContext(mergedOptions));
|
|
267677
267647
|
const result = await maybeQuiet(jsonOutput, () => whitelistAddress(context.clientWrapper, context.substrateAddress, context.signer, address, enable));
|
|
@@ -267707,7 +267677,7 @@ function validateEvmAddress(raw) {
|
|
|
267707
267677
|
}
|
|
267708
267678
|
return getAddress(raw);
|
|
267709
267679
|
}
|
|
267710
|
-
function
|
|
267680
|
+
function handleCommandError2(error2, cmd) {
|
|
267711
267681
|
const jsonOutput = getJsonFlag(cmd);
|
|
267712
267682
|
const message2 = formatErrorMessage(error2);
|
|
267713
267683
|
if (jsonOutput) {
|
|
@@ -267737,7 +267707,7 @@ function attachStoreCommands(root) {
|
|
|
267737
267707
|
}
|
|
267738
267708
|
process.exit(0);
|
|
267739
267709
|
} catch (error2) {
|
|
267740
|
-
|
|
267710
|
+
handleCommandError2(error2, cmd);
|
|
267741
267711
|
}
|
|
267742
267712
|
});
|
|
267743
267713
|
const listCommand = storeCommand.command("list").description("List all values in your Store").option("--json", "Output result as JSON", false);
|
|
@@ -267756,7 +267726,7 @@ function attachStoreCommands(root) {
|
|
|
267756
267726
|
}
|
|
267757
267727
|
process.exit(0);
|
|
267758
267728
|
} catch (error2) {
|
|
267759
|
-
|
|
267729
|
+
handleCommandError2(error2, cmd);
|
|
267760
267730
|
}
|
|
267761
267731
|
});
|
|
267762
267732
|
const namesCommand = storeCommand.command("names").description("List all .dot names in your Store").option("--json", "Output result as JSON", false);
|
|
@@ -267785,7 +267755,7 @@ function attachStoreCommands(root) {
|
|
|
267785
267755
|
}
|
|
267786
267756
|
process.exit(0);
|
|
267787
267757
|
} catch (error2) {
|
|
267788
|
-
|
|
267758
|
+
handleCommandError2(error2, cmd);
|
|
267789
267759
|
}
|
|
267790
267760
|
});
|
|
267791
267761
|
const cidsCommand = storeCommand.command("cids").description("List all uploaded CIDs in your Store").option("--json", "Output result as JSON", false);
|
|
@@ -267814,7 +267784,7 @@ function attachStoreCommands(root) {
|
|
|
267814
267784
|
}
|
|
267815
267785
|
process.exit(0);
|
|
267816
267786
|
} catch (error2) {
|
|
267817
|
-
|
|
267787
|
+
handleCommandError2(error2, cmd);
|
|
267818
267788
|
}
|
|
267819
267789
|
});
|
|
267820
267790
|
const getCommand = storeCommand.command("get <key>").description("Get a value by key (hex bytes32 or string, hashed via keccak256)").option("--json", "Output result as JSON", false);
|
|
@@ -267833,7 +267803,7 @@ function attachStoreCommands(root) {
|
|
|
267833
267803
|
}
|
|
267834
267804
|
process.exit(0);
|
|
267835
267805
|
} catch (error2) {
|
|
267836
|
-
|
|
267806
|
+
handleCommandError2(error2, cmd);
|
|
267837
267807
|
}
|
|
267838
267808
|
});
|
|
267839
267809
|
const setCommand = storeCommand.command("set <key> <value>").description("Set a key-value pair in your Store").option("--json", "Output result as JSON", false);
|
|
@@ -267853,7 +267823,7 @@ function attachStoreCommands(root) {
|
|
|
267853
267823
|
}
|
|
267854
267824
|
process.exit(0);
|
|
267855
267825
|
} catch (error2) {
|
|
267856
|
-
|
|
267826
|
+
handleCommandError2(error2, cmd);
|
|
267857
267827
|
}
|
|
267858
267828
|
});
|
|
267859
267829
|
const deleteCommand = storeCommand.command("delete <key>").description("Delete a value from your Store by key").option("--json", "Output result as JSON", false);
|
|
@@ -267873,7 +267843,7 @@ function attachStoreCommands(root) {
|
|
|
267873
267843
|
}
|
|
267874
267844
|
process.exit(0);
|
|
267875
267845
|
} catch (error2) {
|
|
267876
|
-
|
|
267846
|
+
handleCommandError2(error2, cmd);
|
|
267877
267847
|
}
|
|
267878
267848
|
});
|
|
267879
267849
|
const checkCommand = storeCommand.command("check <address>").description("Check whether an address is authorized or a DotNS controller on your Store").option("--json", "Output result as JSON", false);
|
|
@@ -267893,7 +267863,7 @@ function attachStoreCommands(root) {
|
|
|
267893
267863
|
}
|
|
267894
267864
|
process.exit(0);
|
|
267895
267865
|
} catch (error2) {
|
|
267896
|
-
|
|
267866
|
+
handleCommandError2(error2, cmd);
|
|
267897
267867
|
}
|
|
267898
267868
|
});
|
|
267899
267869
|
const authorizeCommand = storeCommand.command("authorize <address>").description("Authorize an address to write to your Store (setValueFor)").option("--json", "Output result as JSON", false);
|
|
@@ -267914,7 +267884,7 @@ function attachStoreCommands(root) {
|
|
|
267914
267884
|
}
|
|
267915
267885
|
process.exit(0);
|
|
267916
267886
|
} catch (error2) {
|
|
267917
|
-
|
|
267887
|
+
handleCommandError2(error2, cmd);
|
|
267918
267888
|
}
|
|
267919
267889
|
});
|
|
267920
267890
|
const unauthorizeCommand = storeCommand.command("unauthorize <address>").description("Revoke write access from an address on your Store").option("--json", "Output result as JSON", false);
|
|
@@ -267935,7 +267905,7 @@ function attachStoreCommands(root) {
|
|
|
267935
267905
|
}
|
|
267936
267906
|
process.exit(0);
|
|
267937
267907
|
} catch (error2) {
|
|
267938
|
-
|
|
267908
|
+
handleCommandError2(error2, cmd);
|
|
267939
267909
|
}
|
|
267940
267910
|
});
|
|
267941
267911
|
const authorizeControllerCommand = storeCommand.command("authorize-controller <address>").description("Authorize an address as a DotNS controller (locks keys permanently on write)").option("--json", "Output result as JSON", false);
|
|
@@ -267956,7 +267926,7 @@ function attachStoreCommands(root) {
|
|
|
267956
267926
|
}
|
|
267957
267927
|
process.exit(0);
|
|
267958
267928
|
} catch (error2) {
|
|
267959
|
-
|
|
267929
|
+
handleCommandError2(error2, cmd);
|
|
267960
267930
|
}
|
|
267961
267931
|
});
|
|
267962
267932
|
const unauthorizeControllerCommand = storeCommand.command("unauthorize-controller <address>").description("Revoke DotNS controller authorization from an address on your Store").option("--json", "Output result as JSON", false);
|
|
@@ -267977,7 +267947,7 @@ function attachStoreCommands(root) {
|
|
|
267977
267947
|
}
|
|
267978
267948
|
process.exit(0);
|
|
267979
267949
|
} catch (error2) {
|
|
267980
|
-
|
|
267950
|
+
handleCommandError2(error2, cmd);
|
|
267981
267951
|
}
|
|
267982
267952
|
});
|
|
267983
267953
|
const ensureAuthCommand = storeCommand.command("ensure-auth").description("Ensure DotNS system contracts are authorized on your Store").option("--json", "Output result as JSON", false);
|
|
@@ -267987,7 +267957,7 @@ function attachStoreCommands(root) {
|
|
|
267987
267957
|
const jsonOutput = getJsonFlag(cmd);
|
|
267988
267958
|
const context = await maybeQuiet(jsonOutput, () => prepareAssetHubContext(merged));
|
|
267989
267959
|
const { clientWrapper, substrateAddress, signer, evmAddress } = context;
|
|
267990
|
-
const result = await maybeQuiet(jsonOutput, () =>
|
|
267960
|
+
const result = await maybeQuiet(jsonOutput, () => ensureStoreAuthorizations(clientWrapper, substrateAddress, signer, evmAddress));
|
|
267991
267961
|
if (jsonOutput) {
|
|
267992
267962
|
console.log(JSON.stringify(result));
|
|
267993
267963
|
} else {
|
|
@@ -267997,7 +267967,7 @@ function attachStoreCommands(root) {
|
|
|
267997
267967
|
}
|
|
267998
267968
|
process.exit(0);
|
|
267999
267969
|
} catch (error2) {
|
|
268000
|
-
|
|
267970
|
+
handleCommandError2(error2, cmd);
|
|
268001
267971
|
}
|
|
268002
267972
|
});
|
|
268003
267973
|
}
|