bulletin-deploy 0.18.4 → 0.19.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/auth-config.js +4 -4
- package/dist/bug-report.js +4 -4
- package/dist/chain-health.js +3 -3
- package/dist/{chunk-JGIPHFBT.js → chunk-7G554R3V.js} +2 -2
- package/dist/{chunk-GZ4O5DIU.js → chunk-CQSTGES3.js} +1 -1
- package/dist/chunk-DMNLTQGA.js +64 -0
- package/dist/{chunk-CVQ7DJHG.js → chunk-I5PNPQZO.js} +64 -3
- package/dist/{chunk-7I3MTGOR.js → chunk-K5SP4OUC.js} +19 -1
- package/dist/{chunk-5HFXRNCQ.js → chunk-KFUL2F3N.js} +1 -1
- package/dist/{chunk-5MS64TTR.js → chunk-LE73Q6DA.js} +2 -2
- package/dist/{chunk-MJCXPKBL.js → chunk-NHH24DSU.js} +62 -14
- package/dist/{chunk-WEVSXHII.js → chunk-NKDGBZBP.js} +1 -1
- package/dist/{chunk-A55GRHCX.js → chunk-NVWPB3S3.js} +3 -3
- package/dist/{chunk-HDGD5FYX.js → chunk-NYNAUG4V.js} +13 -4
- package/dist/{chunk-WCGCM45C.js → chunk-OYQAO5ED.js} +11 -44
- package/dist/{chunk-TTUXQMD3.js → chunk-Q3DZJVLB.js} +1 -1
- package/dist/{chunk-STXAFUTQ.js → chunk-QJJJA4PQ.js} +4 -1
- package/dist/{chunk-E7PNP2NP.js → chunk-WN4Y7P24.js} +3 -3
- package/dist/{chunk-RXV677CJ.js → chunk-YTRNJMI4.js} +7 -36
- package/dist/{chunk-4NIOCONP.js → chunk-ZD43DXG6.js} +1 -1
- package/dist/{chunk-K23BCUAG.js → chunk-ZI5RS5PN.js} +21 -16
- package/dist/chunk-probe.js +3 -3
- package/dist/commands/login.js +13 -13
- package/dist/commands/logout.js +5 -5
- package/dist/commands/transfer.js +6 -6
- package/dist/commands/whoami.js +4 -4
- package/dist/deploy-actors.js +8 -8
- package/dist/deploy.d.ts +1 -1
- package/dist/deploy.js +13 -13
- package/dist/dotns-protocol.d.ts +32 -1
- package/dist/dotns-protocol.js +5 -1
- package/dist/dotns.d.ts +12 -3
- package/dist/dotns.js +8 -6
- package/dist/environments.d.ts +5 -2
- package/dist/environments.js +3 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +21 -20
- package/dist/manifest/byte-budget.js +2 -1
- package/dist/manifest/compose.d.ts +20 -0
- package/dist/manifest/compose.js +8 -0
- package/dist/manifest/config-load.js +2 -2
- package/dist/manifest/publish.js +18 -17
- package/dist/manifest/schema.js +1 -1
- package/dist/manifest/types.d.ts +29 -1
- package/dist/memory-report.js +2 -2
- package/dist/merkle.js +13 -13
- package/dist/personhood/bootstrap.js +7 -7
- package/dist/personhood/people-client.js +6 -6
- package/dist/run-state.js +1 -1
- package/dist/sss-allowance-cache.js +5 -5
- package/dist/storage-signer.js +13 -13
- package/dist/telemetry.d.ts +1 -1
- package/dist/telemetry.js +2 -2
- package/dist/version-check.js +3 -3
- package/docs/product-manifest.md +76 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -71,7 +71,7 @@ Key options:
|
|
|
71
71
|
| `--no-transfer-to-signedin-user` | When signed in, sign every DotNS tx with your mobile session instead of the default register-as-worker-then-hand-over flow. |
|
|
72
72
|
| `--to <0xH160>` | Recipient address for the `transfer` subcommand. Defaults to the signed-in account. |
|
|
73
73
|
| `--js-merkle` | Use pure-JS merkleization (no IPFS Kubo binary required). |
|
|
74
|
-
| `--config <path>` | Explicit path to `bulletin-deploy.config.ts` for product deploys. |
|
|
74
|
+
| `--config <path>` | Explicit path to `bulletin-deploy.config.ts` for product deploys. See [`docs/product-manifest.md`](docs/product-manifest.md). |
|
|
75
75
|
| `--tag "..."` | Label the deploy in telemetry. |
|
|
76
76
|
| `--version` | Print the installed version and exit. |
|
|
77
77
|
|
package/dist/auth-config.js
CHANGED
|
@@ -9,12 +9,12 @@ import {
|
|
|
9
9
|
getPeopleChainEndpoints,
|
|
10
10
|
hasPersistedSession,
|
|
11
11
|
resolveBulletinEndpoints
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-LE73Q6DA.js";
|
|
13
13
|
import "./chunk-TSPERKUS.js";
|
|
14
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-NYNAUG4V.js";
|
|
15
15
|
import "./chunk-ZOC4GITL.js";
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-QJJJA4PQ.js";
|
|
17
|
+
import "./chunk-WN4Y7P24.js";
|
|
18
18
|
export {
|
|
19
19
|
DOT_DAPP_ID,
|
|
20
20
|
DOT_DERIVATION_INDEX,
|
package/dist/bug-report.js
CHANGED
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
offerBugReport,
|
|
11
11
|
scrubSecrets,
|
|
12
12
|
setDeployContext
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
16
|
-
import "./chunk-
|
|
13
|
+
} from "./chunk-NVWPB3S3.js";
|
|
14
|
+
import "./chunk-Q3DZJVLB.js";
|
|
15
|
+
import "./chunk-QJJJA4PQ.js";
|
|
16
|
+
import "./chunk-WN4Y7P24.js";
|
|
17
17
|
export {
|
|
18
18
|
buildCliFlagsSummary,
|
|
19
19
|
buildLabels,
|
package/dist/chain-health.js
CHANGED
|
@@ -3,9 +3,9 @@ import {
|
|
|
3
3
|
DEFAULT_WINDOW_BLOCKS,
|
|
4
4
|
MAX_SPANS_PER_SAMPLER,
|
|
5
5
|
endpointHost
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-KFUL2F3N.js";
|
|
7
|
+
import "./chunk-QJJJA4PQ.js";
|
|
8
|
+
import "./chunk-WN4Y7P24.js";
|
|
9
9
|
export {
|
|
10
10
|
ChainHealthSampler,
|
|
11
11
|
DEFAULT_WINDOW_BLOCKS,
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
} from "./chunk-5FLTDWWP.js";
|
|
5
5
|
import {
|
|
6
6
|
DEFAULT_MNEMONIC
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-NHH24DSU.js";
|
|
8
8
|
import {
|
|
9
9
|
DOT_PRODUCT_ID
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-LE73Q6DA.js";
|
|
11
11
|
|
|
12
12
|
// src/deploy-actors.ts
|
|
13
13
|
var DEFAULT_WORKER_SURI = DEFAULT_MNEMONIC;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// src/manifest/compose.ts
|
|
2
|
+
function composeRoot(config, iconCid) {
|
|
3
|
+
const labels = config.domain.split(".");
|
|
4
|
+
const selfLabel = (labels[labels.length - 2] ?? labels[0]).toLowerCase();
|
|
5
|
+
const trustedProducts = normalizeTrustedProducts(
|
|
6
|
+
config.trustedProducts,
|
|
7
|
+
selfLabel
|
|
8
|
+
);
|
|
9
|
+
return {
|
|
10
|
+
$v: 1,
|
|
11
|
+
displayName: config.displayName,
|
|
12
|
+
description: config.description,
|
|
13
|
+
icon: { cid: iconCid, format: config.icon.format },
|
|
14
|
+
...trustedProducts !== void 0 ? { trustedProducts } : {}
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function normalizeTrustedProducts(input, selfLabel) {
|
|
18
|
+
if (input === void 0) return void 0;
|
|
19
|
+
const ids = Object.keys(input).filter(
|
|
20
|
+
(id) => id.toLowerCase() !== selfLabel && input[id].length > 0
|
|
21
|
+
).sort();
|
|
22
|
+
if (ids.length === 0) return void 0;
|
|
23
|
+
return Object.fromEntries(
|
|
24
|
+
ids.map((id) => [id, normalizeGrants(input[id])])
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
function normalizeGrants(grants) {
|
|
28
|
+
const unique = [...new Set(grants)];
|
|
29
|
+
return unique.includes("all") ? ["all"] : unique.sort();
|
|
30
|
+
}
|
|
31
|
+
function composeExecutable(exec) {
|
|
32
|
+
if (exec.kind === "app") {
|
|
33
|
+
return "manifest" in exec ? exec.manifest : { $v: 1, kind: "app", appVersion: exec.appVersion };
|
|
34
|
+
}
|
|
35
|
+
if (exec.kind === "widget") {
|
|
36
|
+
return {
|
|
37
|
+
$v: 1,
|
|
38
|
+
kind: "widget",
|
|
39
|
+
appVersion: exec.appVersion,
|
|
40
|
+
dimensions: exec.dimensions,
|
|
41
|
+
...exec.description !== void 0 ? { description: exec.description } : {}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
if (exec.kind === "funding") {
|
|
45
|
+
return {
|
|
46
|
+
$v: 1,
|
|
47
|
+
kind: "funding",
|
|
48
|
+
appVersion: exec.appVersion,
|
|
49
|
+
modes: exec.modes
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
$v: 1,
|
|
54
|
+
kind: "worker",
|
|
55
|
+
appVersion: exec.appVersion,
|
|
56
|
+
entrypoint: exec.entrypoint,
|
|
57
|
+
includes: exec.includes
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export {
|
|
62
|
+
composeRoot,
|
|
63
|
+
composeExecutable
|
|
64
|
+
};
|
|
@@ -11,15 +11,53 @@ var EXECUTABLE_KINDS = [
|
|
|
11
11
|
KIND_WORKER
|
|
12
12
|
];
|
|
13
13
|
var FUNDING_MODES = ["CARD", "BANK", "CRYPTO"];
|
|
14
|
+
var GRANTED_VALUES = ["all", "storage", "context"];
|
|
14
15
|
var LABEL = String.raw`(?!-)[a-z0-9-]{1,63}(?<!-)`;
|
|
15
16
|
var TLD_FRAGMENT = "[a-z]{2,63}";
|
|
16
17
|
var DOMAIN_RE = new RegExp(`^${LABEL}(\\.${LABEL})*\\.${TLD_FRAGMENT}$`, "i");
|
|
18
|
+
var PRODUCT_LABEL_RE = new RegExp(`^${LABEL}$`);
|
|
17
19
|
function isPlainObject(value) {
|
|
18
20
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19
21
|
}
|
|
20
22
|
function isNonEmptyString(value) {
|
|
21
23
|
return typeof value === "string" && value.length > 0;
|
|
22
24
|
}
|
|
25
|
+
function validateTrustedProducts(value, label, strict) {
|
|
26
|
+
if (!isPlainObject(value))
|
|
27
|
+
return [`${label} trustedProducts must be an object`];
|
|
28
|
+
const errors = [];
|
|
29
|
+
for (const [key, grants] of Object.entries(value)) {
|
|
30
|
+
if (key.length === 0) {
|
|
31
|
+
errors.push(`${label} trustedProducts key must not be empty`);
|
|
32
|
+
} else if (key.includes(".")) {
|
|
33
|
+
if (strict) {
|
|
34
|
+
errors.push(
|
|
35
|
+
`${label} trustedProducts key '${key}' must not include a TLD suffix (the host appends its own TLD) \u2014 use '${key.split(".")[0]}' instead of '${key}'`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
} else if (key !== key.toLowerCase()) {
|
|
39
|
+
errors.push(`${label} trustedProducts key '${key}' must be lowercase`);
|
|
40
|
+
} else if (!PRODUCT_LABEL_RE.test(key)) {
|
|
41
|
+
errors.push(
|
|
42
|
+
`${label} trustedProducts key '${key}' must be a valid dotNS label`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
if (!Array.isArray(grants)) {
|
|
46
|
+
errors.push(`${label} trustedProducts['${key}'] must be an array`);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (strict) {
|
|
50
|
+
errors.push(
|
|
51
|
+
...rejectUnknownEntries(
|
|
52
|
+
grants,
|
|
53
|
+
GRANTED_VALUES,
|
|
54
|
+
`${label} trustedProducts['${key}']`
|
|
55
|
+
)
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return errors;
|
|
60
|
+
}
|
|
23
61
|
function isAppVersion(value) {
|
|
24
62
|
if (!Array.isArray(value)) return false;
|
|
25
63
|
if (value.length !== 3 && value.length !== 4) return false;
|
|
@@ -32,6 +70,11 @@ function isAppVersion(value) {
|
|
|
32
70
|
function rejectUnknownFields(input, allowed, prefix) {
|
|
33
71
|
return Object.keys(input).filter((key) => !allowed.includes(key)).map((key) => `${prefix}contains unknown field '${key}'`);
|
|
34
72
|
}
|
|
73
|
+
function rejectUnknownEntries(values, allowed, describe) {
|
|
74
|
+
return values.filter((value) => !allowed.includes(value)).map(
|
|
75
|
+
(value) => `${describe} entries must be one of ${allowed.join(", ")} (got ${JSON.stringify(value)})`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
35
78
|
function validateRelativeEntrypoint(value, suffix, prefix) {
|
|
36
79
|
if (!isNonEmptyString(value))
|
|
37
80
|
return [`${prefix}entrypoint must be a non-empty string`];
|
|
@@ -246,9 +289,7 @@ function validateFundingFields(input, p) {
|
|
|
246
289
|
if (!Array.isArray(input.modes) || input.modes.length === 0) {
|
|
247
290
|
return [`${p}modes must be a non-empty array`];
|
|
248
291
|
}
|
|
249
|
-
return input.modes
|
|
250
|
-
(mode) => `${p}modes entries must be one of ${FUNDING_MODES.join(", ")} (got ${JSON.stringify(mode)})`
|
|
251
|
-
);
|
|
292
|
+
return rejectUnknownEntries(input.modes, FUNDING_MODES, `${p}modes`);
|
|
252
293
|
}
|
|
253
294
|
function validateWorkerFields(input, p) {
|
|
254
295
|
const errors = [];
|
|
@@ -294,6 +335,16 @@ function validateRootManifest(input) {
|
|
|
294
335
|
);
|
|
295
336
|
}
|
|
296
337
|
}
|
|
338
|
+
if (input.trustedProducts !== void 0) {
|
|
339
|
+
errors.push(
|
|
340
|
+
...validateTrustedProducts(
|
|
341
|
+
input.trustedProducts,
|
|
342
|
+
"root manifest",
|
|
343
|
+
/* strict */
|
|
344
|
+
false
|
|
345
|
+
)
|
|
346
|
+
);
|
|
347
|
+
}
|
|
297
348
|
return errors.length === 0 ? { ok: true, value: input } : { ok: false, errors };
|
|
298
349
|
}
|
|
299
350
|
function validateExecutableManifest(input) {
|
|
@@ -363,6 +414,16 @@ function validateProductConfig(input) {
|
|
|
363
414
|
);
|
|
364
415
|
}
|
|
365
416
|
}
|
|
417
|
+
if (input.trustedProducts !== void 0) {
|
|
418
|
+
errors.push(
|
|
419
|
+
...validateTrustedProducts(
|
|
420
|
+
input.trustedProducts,
|
|
421
|
+
"product config",
|
|
422
|
+
/* strict */
|
|
423
|
+
true
|
|
424
|
+
)
|
|
425
|
+
);
|
|
426
|
+
}
|
|
366
427
|
if (!Array.isArray(input.executables) || input.executables.length === 0) {
|
|
367
428
|
errors.push("product config executables must be a non-empty array");
|
|
368
429
|
} else {
|
|
@@ -16,12 +16,28 @@ var DOTNS_ABI_PROFILES = {
|
|
|
16
16
|
discriminator: "isPopIssued"
|
|
17
17
|
}
|
|
18
18
|
};
|
|
19
|
+
var HIGHEST_VERIFIED_DOTNS_RELEASE = "0.8.0";
|
|
20
|
+
function classifyDeclaredProtocolVersion(raw) {
|
|
21
|
+
if (!raw) return null;
|
|
22
|
+
const parts = raw.split("-")[0].split(".").slice(0, 3);
|
|
23
|
+
if (parts.length < 2 || !parts.every((part) => /^\d+$/.test(part))) return null;
|
|
24
|
+
return {
|
|
25
|
+
raw,
|
|
26
|
+
profile: "v0.6.0",
|
|
27
|
+
// Numeric collation, so 0.10.0 sorts above 0.8.0 rather than below it.
|
|
28
|
+
aboveVerifiedCeiling: parts.join(".").localeCompare(HIGHEST_VERIFIED_DOTNS_RELEASE, void 0, { numeric: true }) > 0
|
|
29
|
+
};
|
|
30
|
+
}
|
|
19
31
|
function classifyProtocolVersion(probe) {
|
|
20
32
|
const { hasCode, pricingVersionOk, startingPriceOk, isPopIssuedOk } = probe;
|
|
21
33
|
if (hasCode === false) {
|
|
22
34
|
return {
|
|
23
35
|
profile: null,
|
|
24
|
-
reason:
|
|
36
|
+
reason: (
|
|
37
|
+
// No config pointer here: this function has no environment context, so it
|
|
38
|
+
// cannot know which file holds the address. The caller appends that.
|
|
39
|
+
"No contract deployed at this address: could not detect the DotNS ABI profile because no contract code was found here."
|
|
40
|
+
)
|
|
25
41
|
};
|
|
26
42
|
}
|
|
27
43
|
if (pricingVersionOk) return { profile: isPopIssuedOk === true ? "v0.6.0" : "v0.5.8-rc1" };
|
|
@@ -143,6 +159,8 @@ function getAdapter(profile) {
|
|
|
143
159
|
|
|
144
160
|
export {
|
|
145
161
|
DOTNS_ABI_PROFILES,
|
|
162
|
+
HIGHEST_VERIFIED_DOTNS_RELEASE,
|
|
163
|
+
classifyDeclaredProtocolVersion,
|
|
146
164
|
classifyProtocolVersion,
|
|
147
165
|
OLD_CONTROLLER_ABI,
|
|
148
166
|
V0_5_8_RC1_CONTROLLER_ABI,
|
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
} from "./chunk-TSPERKUS.js";
|
|
4
4
|
import {
|
|
5
5
|
loadEnvironments
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-NYNAUG4V.js";
|
|
7
7
|
import {
|
|
8
8
|
VERSION
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-QJJJA4PQ.js";
|
|
10
10
|
|
|
11
11
|
// src/auth-config.ts
|
|
12
12
|
import { existsSync, readdirSync } from "fs";
|
|
@@ -7,13 +7,13 @@ import {
|
|
|
7
7
|
} from "./chunk-AYAVRPAP.js";
|
|
8
8
|
import {
|
|
9
9
|
validateContractAddresses
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-NYNAUG4V.js";
|
|
11
11
|
import {
|
|
12
12
|
NonRetryableError
|
|
13
13
|
} from "./chunk-ZOC4GITL.js";
|
|
14
14
|
import {
|
|
15
15
|
ChainHealthSampler
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-KFUL2F3N.js";
|
|
17
17
|
import {
|
|
18
18
|
captureWarning,
|
|
19
19
|
markCodePath,
|
|
@@ -21,14 +21,16 @@ import {
|
|
|
21
21
|
setDeploySentryTag,
|
|
22
22
|
truncateAddress,
|
|
23
23
|
withSpan
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-QJJJA4PQ.js";
|
|
25
25
|
import {
|
|
26
|
+
HIGHEST_VERIFIED_DOTNS_RELEASE,
|
|
26
27
|
POP_CONTROLLER_PROBE_ABI,
|
|
27
28
|
PROTOCOL_PROBE_LABEL,
|
|
29
|
+
classifyDeclaredProtocolVersion,
|
|
28
30
|
classifyProtocolVersion,
|
|
29
31
|
getAdapter,
|
|
30
32
|
withTenPercentBuffer
|
|
31
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-K5SP4OUC.js";
|
|
32
34
|
|
|
33
35
|
// src/dotns.ts
|
|
34
36
|
import crypto from "crypto";
|
|
@@ -370,7 +372,8 @@ var DOTNS_REGISTRAR_ABI = [
|
|
|
370
372
|
];
|
|
371
373
|
var DOTNS_REGISTRAR_TRANSFER_ABI = [
|
|
372
374
|
...DOTNS_REGISTRAR_ABI,
|
|
373
|
-
{ inputs: [{ name: "from", type: "address" }, { name: "to", type: "address" }, { name: "tokenId", type: "uint256" }], name: "transferFrom", outputs: [], stateMutability: "payable", type: "function" }
|
|
375
|
+
{ inputs: [{ name: "from", type: "address" }, { name: "to", type: "address" }, { name: "tokenId", type: "uint256" }], name: "transferFrom", outputs: [], stateMutability: "payable", type: "function" },
|
|
376
|
+
{ inputs: [{ name: "tokenId", type: "uint256" }], name: "isSoulbound", outputs: [{ name: "", type: "bool" }], stateMutability: "view", type: "function" }
|
|
374
377
|
];
|
|
375
378
|
var POP_RULES_ABI = [
|
|
376
379
|
{ inputs: [{ name: "name", type: "string" }], name: "classifyName", outputs: [{ name: "requirement", type: "uint8" }, { name: "message", type: "string" }], stateMutability: "pure", type: "function" },
|
|
@@ -437,7 +440,9 @@ var DOTNS_CONTENT_RESOLVER_ABI = [
|
|
|
437
440
|
];
|
|
438
441
|
var DOTNS_PROTOCOL_REGISTRY_ABI = [
|
|
439
442
|
{ inputs: [], name: "tld", outputs: [{ name: "", type: "string" }], stateMutability: "view", type: "function" },
|
|
440
|
-
{ inputs: [], name: "tldNode", outputs: [{ name: "", type: "bytes32" }], stateMutability: "view", type: "function" }
|
|
443
|
+
{ inputs: [], name: "tldNode", outputs: [{ name: "", type: "bytes32" }], stateMutability: "view", type: "function" },
|
|
444
|
+
// v0.8.0 and up; reverts below it, empty until a release is declared.
|
|
445
|
+
{ inputs: [], name: "protocolVersion", outputs: [{ name: "", type: "string" }], stateMutability: "view", type: "function" }
|
|
441
446
|
];
|
|
442
447
|
var DOTNS_TEXT_RESOLVER_ABI = [
|
|
443
448
|
{ inputs: [{ name: "node", type: "bytes32" }, { name: "key", type: "string" }, { name: "value", type: "string" }], name: "setText", outputs: [], stateMutability: "nonpayable", type: "function" },
|
|
@@ -822,6 +827,9 @@ function isShortNameBand(baseLength) {
|
|
|
822
827
|
function shortNamesClosedReason(label, baseLength, tld, environmentId) {
|
|
823
828
|
return `${label}.${tld} has a ${baseLength}-character base and short names are not on sale on ${environmentId ?? "this environment"}. PopRules.shortNamesEnabled is off, which closes the 6 to 8 character band to every signer, whatever their personhood status. Use a base of 9 characters or more, for example ${exampleNoStatusLabel(label, tld)}.`;
|
|
824
829
|
}
|
|
830
|
+
function soulboundTransferReason(label, tld) {
|
|
831
|
+
return `${label}.${tld} is soulbound and cannot be transferred. It was issued through the PoP gateway, which binds a name to the account that received it. Nothing clears the flag, so no account can move this name at any point in the future.`;
|
|
832
|
+
}
|
|
825
833
|
function parseDomainName(input, tld = DEFAULT_TLD) {
|
|
826
834
|
const configuredSuffix = `.${tld}`;
|
|
827
835
|
let name;
|
|
@@ -1324,6 +1332,7 @@ var DotNS = class _DotNS {
|
|
|
1324
1332
|
_isPhoneSigner = false;
|
|
1325
1333
|
_localMnemonic = null;
|
|
1326
1334
|
_contracts = CONTRACTS;
|
|
1335
|
+
_contractSources = {};
|
|
1327
1336
|
_nativeToEthRatio = NATIVE_TO_ETH_RATIO;
|
|
1328
1337
|
_environmentId = null;
|
|
1329
1338
|
// #1095: the resolved env's declared `network`, when connect() was given
|
|
@@ -1509,9 +1518,10 @@ var DotNS = class _DotNS {
|
|
|
1509
1518
|
this.assetHubEndpoints = options.assetHubEndpoints;
|
|
1510
1519
|
}
|
|
1511
1520
|
if (options.contracts && Object.keys(options.contracts).length > 0) {
|
|
1512
|
-
validateContractAddresses(options.contracts, options.environmentId ?? "unknown");
|
|
1521
|
+
validateContractAddresses(options.contracts, options.environmentId ?? "unknown", options.contractSources);
|
|
1513
1522
|
this._contracts = { ...CONTRACTS, ...options.contracts };
|
|
1514
1523
|
}
|
|
1524
|
+
this._contractSources = options.contractSources ?? {};
|
|
1515
1525
|
if (options.environmentId) {
|
|
1516
1526
|
this._environmentId = options.environmentId;
|
|
1517
1527
|
}
|
|
@@ -1901,7 +1911,8 @@ var DotNS = class _DotNS {
|
|
|
1901
1911
|
});
|
|
1902
1912
|
}
|
|
1903
1913
|
/**
|
|
1904
|
-
* Low-level dry-run read against DotnsProtocolRegistry (tld() / tldNode()
|
|
1914
|
+
* Low-level dry-run read against DotnsProtocolRegistry (tld() / tldNode() /
|
|
1915
|
+
* protocolVersion()).
|
|
1905
1916
|
* Deliberately does NOT reuse contractCall/contractCallNullable: both of
|
|
1906
1917
|
* those throw on a revert or on empty data, which would make "contract
|
|
1907
1918
|
* doesn't support this function yet" indistinguishable from "the RPC call
|
|
@@ -2000,25 +2011,43 @@ var DotNS = class _DotNS {
|
|
|
2000
2011
|
const popRulesAddress = this._contracts.POP_RULES;
|
|
2001
2012
|
const popControllerAddress = this._contracts.DOTNS_POP_CONTROLLER;
|
|
2002
2013
|
const env = this._environmentId ?? "unknown";
|
|
2003
|
-
const [hasCodeResult, pricingVersionOk, startingPriceOk, isPopIssuedOk] = await Promise.all([
|
|
2014
|
+
const [hasCodeResult, pricingVersionOk, startingPriceOk, isPopIssuedOk, declaredResult] = await Promise.all([
|
|
2004
2015
|
this.clientWrapper.hasContractCode(popRulesAddress),
|
|
2005
2016
|
this.probeViewFunctionOk(popRulesAddress, getAdapter("v0.5.8-rc1").popRulesAbi, "pricingVersion", []),
|
|
2006
2017
|
this.probeViewFunctionOk(popRulesAddress, getAdapter("poprules-startingPrice").popRulesAbi, "startingPrice", []),
|
|
2007
|
-
popControllerAddress ? this.probeViewFunctionOk(popControllerAddress, POP_CONTROLLER_PROBE_ABI, "isPopIssued", [PROTOCOL_PROBE_LABEL]) : Promise.resolve(null)
|
|
2018
|
+
popControllerAddress ? this.probeViewFunctionOk(popControllerAddress, POP_CONTROLLER_PROBE_ABI, "isPopIssued", [PROTOCOL_PROBE_LABEL]) : Promise.resolve(null),
|
|
2019
|
+
// Informational, so an RPC failure must not fail a connect the probes
|
|
2020
|
+
// can classify. Caught here, not in dryRunRegistryString, which
|
|
2021
|
+
// propagates on purpose for tld() — swallowing there picks a wrong TLD.
|
|
2022
|
+
this.dryRunRegistryString("protocolVersion").catch(() => ({ ok: false }))
|
|
2008
2023
|
]);
|
|
2009
2024
|
const classification = classifyProtocolVersion({ hasCode: hasCodeResult, pricingVersionOk, startingPriceOk, isPopIssuedOk });
|
|
2010
2025
|
if (classification.profile === null) {
|
|
2011
|
-
throw new Error(`${env} (${dotnsContractName(popRulesAddress, this._contracts)} ${popRulesAddress}): ${classification.reason}`);
|
|
2026
|
+
throw new Error(`${env} (${dotnsContractName(popRulesAddress, this._contracts)} ${popRulesAddress}): ${classification.reason}${hasCodeResult === true ? "" : this.contractSourceHint("POP_RULES")}`);
|
|
2012
2027
|
}
|
|
2013
2028
|
const profile = classification.profile;
|
|
2029
|
+
const declared = classifyDeclaredProtocolVersion(declaredResult.ok ? declaredResult.value : null);
|
|
2014
2030
|
this._protocolVersion = profile;
|
|
2015
2031
|
this._adapter = getAdapter(profile);
|
|
2016
2032
|
setDeployAttribute("deploy.dotns.protocol_version", profile);
|
|
2017
|
-
|
|
2033
|
+
setDeployAttribute("deploy.dotns.declared_release", declaredResult.ok ? declaredResult.value || "undeclared" : "unavailable");
|
|
2034
|
+
console.log(` DotNS ABI profile ${profile} detected on ${env}${declared ? ` (declares DotNS ${declared.raw})` : ""}`);
|
|
2035
|
+
if (declared && declared.profile !== profile) {
|
|
2036
|
+
console.log(` NOTE: ${env} declares DotNS ${declared.raw}, which is the ${declared.profile} profile, but the probes detect ${profile}. Using ${profile}: the probes read the ABI that is actually deployed.`);
|
|
2037
|
+
}
|
|
2038
|
+
if (declared?.aboveVerifiedCeiling) {
|
|
2039
|
+
console.log(` WARNING: ${env} declares DotNS ${declared.raw}, newer than ${HIGHEST_VERIFIED_DOTNS_RELEASE} \u2014 the newest release whose ABI has been checked against this client. Continuing on the ${profile} profile, which is correct only if that release changed nothing bulletin-deploy calls. Re-run the upstream ABI diff.`);
|
|
2040
|
+
}
|
|
2018
2041
|
if (profile === "v0.5.8-rc1" && pricingVersionOk && isPopIssuedOk === null) {
|
|
2019
2042
|
console.log(` NOTE: could not confirm whether ${env} is v0.5.8-rc1 or v0.6.0 \u2014 DOTNS_POP_CONTROLLER has no configured address here, so the isPopIssued discriminator probe was never attempted. Defaulting to v0.5.8-rc1 label semantics (registration itself is unaffected: both profiles share an identical ABI/adapter).`);
|
|
2020
2043
|
}
|
|
2021
2044
|
}
|
|
2045
|
+
// Ends an address error with where that address came from. A key with no
|
|
2046
|
+
// recorded source fell through to the defaults compiled into this module.
|
|
2047
|
+
contractSourceHint(name) {
|
|
2048
|
+
const src = this._contractSources[name];
|
|
2049
|
+
return src ? ` This address came from ${src}.` : ` No environment or --contract supplied ${name}, so this is the built-in default address.`;
|
|
2050
|
+
}
|
|
2022
2051
|
async contractCall(contractAddress, contractAbi, functionName, args = []) {
|
|
2023
2052
|
this.ensureConnected();
|
|
2024
2053
|
if (!this.clientWrapper) throw new Error("contractCall: polkadot-api client not available");
|
|
@@ -2050,12 +2079,12 @@ var DotNS = class _DotNS {
|
|
|
2050
2079
|
const env = this._environmentId ?? "(unset)";
|
|
2051
2080
|
if (hasCode === false) {
|
|
2052
2081
|
throw new Error(
|
|
2053
|
-
`No contract deployed at ${contractAddress} (${name}) env=${env} \u2014 the dry-run call to ${functionName} returned empty success data, which on pallet-revive means the target address has no contract code.
|
|
2082
|
+
`No contract deployed at ${contractAddress} (${name}) env=${env} \u2014 the dry-run call to ${functionName} returned empty success data, which on pallet-revive means the target address has no contract code.${this.contractSourceHint(name)}`
|
|
2054
2083
|
);
|
|
2055
2084
|
}
|
|
2056
2085
|
if (hasCode === null) {
|
|
2057
2086
|
throw new Error(
|
|
2058
|
-
`Contract call returned empty data \u2014 contract=${name} (${contractAddress}) env=${env} functionName=${functionName}. Could not verify whether contract code exists at this address (runtime code-presence query failed); investigate the contract/ABI or the configured address
|
|
2087
|
+
`Contract call returned empty data \u2014 contract=${name} (${contractAddress}) env=${env} functionName=${functionName}. Could not verify whether contract code exists at this address (runtime code-presence query failed); investigate the contract/ABI or the configured address.${this.contractSourceHint(name)}`
|
|
2059
2088
|
);
|
|
2060
2089
|
}
|
|
2061
2090
|
throw new Error(
|
|
@@ -2350,6 +2379,21 @@ var DotNS = class _DotNS {
|
|
|
2350
2379
|
if (authorised !== null) return { authorised, owner };
|
|
2351
2380
|
return { authorised: owner !== null && owner.toLowerCase() === account.toLowerCase(), owner };
|
|
2352
2381
|
}
|
|
2382
|
+
/** False when the registrar gave no usable answer, including one too old to
|
|
2383
|
+
* have the function at all: let the chain refuse rather than guess. A read
|
|
2384
|
+
* that never completed propagates, so a network blip is not "not soulbound". */
|
|
2385
|
+
async readIsSoulbound(tokenId) {
|
|
2386
|
+
try {
|
|
2387
|
+
return await withTimeout(
|
|
2388
|
+
this.contractCall(this._contracts.DOTNS_REGISTRAR, DOTNS_REGISTRAR_TRANSFER_ABI, "isSoulbound", [tokenId]),
|
|
2389
|
+
3e4,
|
|
2390
|
+
"isSoulbound"
|
|
2391
|
+
) === true;
|
|
2392
|
+
} catch (e) {
|
|
2393
|
+
if (READ_NEVER_COMPLETED_RE.test(e?.message ?? String(e))) throw e;
|
|
2394
|
+
return false;
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2353
2397
|
/** Live transfer-fee quote. transferFloor is a pure PopRules view — it
|
|
2354
2398
|
* classifies the label and reads both tiers, so it works BEFORE the name is
|
|
2355
2399
|
* registered (unlike quoteTransferFee, which reverts on an unregistered token). */
|
|
@@ -2379,6 +2423,9 @@ var DotNS = class _DotNS {
|
|
|
2379
2423
|
if (owner.toLowerCase() !== this.evmAddress.toLowerCase()) {
|
|
2380
2424
|
throw new Error(`Cannot transfer ${validated}.${this._tld}: it is owned by ${owner}, not the worker ${this.evmAddress}.`);
|
|
2381
2425
|
}
|
|
2426
|
+
if (await this.readIsSoulbound(tokenId)) {
|
|
2427
|
+
throw new NonRetryableError(soulboundTransferReason(validated, this._tld));
|
|
2428
|
+
}
|
|
2382
2429
|
const { feeWei, feeNative } = await this.quoteTransferFloorNative(validated, this.evmAddress, toH160);
|
|
2383
2430
|
const txRes = await this.contractTransaction(
|
|
2384
2431
|
this._contracts.DOTNS_REGISTRAR,
|
|
@@ -3808,6 +3855,7 @@ export {
|
|
|
3808
3855
|
classifyDotnsLabel,
|
|
3809
3856
|
canRegister,
|
|
3810
3857
|
shortNamesClosedReason,
|
|
3858
|
+
soulboundTransferReason,
|
|
3811
3859
|
parseDomainName,
|
|
3812
3860
|
parseProofOfPersonhoodStatus,
|
|
3813
3861
|
popStatusName,
|
|
@@ -2,15 +2,15 @@ import {
|
|
|
2
2
|
classifyErrorArea,
|
|
3
3
|
isInteractive,
|
|
4
4
|
promptYesNo
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-Q3DZJVLB.js";
|
|
6
6
|
import {
|
|
7
7
|
VERSION,
|
|
8
8
|
getCurrentSentryTraceId,
|
|
9
9
|
resolveIssueRepoSlug
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-QJJJA4PQ.js";
|
|
11
11
|
import {
|
|
12
12
|
package_default
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-WN4Y7P24.js";
|
|
14
14
|
|
|
15
15
|
// src/bug-report.ts
|
|
16
16
|
import { execSync, execFileSync } from "child_process";
|
|
@@ -509,15 +509,23 @@ var ZERO_ADDRESS = "0x" + "0".repeat(40);
|
|
|
509
509
|
function isValidContractAddress(addr) {
|
|
510
510
|
return typeof addr === "string" && EVM_ADDRESS_RE.test(addr) && addr.toLowerCase() !== ZERO_ADDRESS;
|
|
511
511
|
}
|
|
512
|
-
function validateContractAddresses(contracts, envId) {
|
|
512
|
+
function validateContractAddresses(contracts, envId, sources) {
|
|
513
513
|
for (const [name, addr] of Object.entries(contracts)) {
|
|
514
514
|
if (!isValidContractAddress(addr)) {
|
|
515
515
|
throw new Error(
|
|
516
|
-
`Invalid contract address for ${name} in environment ${envId}: ${addr}. Check assets/environments.json against https://github.com/paritytech/dotns#deployments`
|
|
516
|
+
`Invalid contract address for ${name} in environment ${envId}: ${addr}. ` + (sources?.[name] ? `This address came from ${sources[name]}.` : `Check assets/environments.json against https://github.com/paritytech/dotns#deployments`)
|
|
517
517
|
);
|
|
518
518
|
}
|
|
519
519
|
}
|
|
520
520
|
}
|
|
521
|
+
function describeContractSources(envContracts, cliContracts, source, userFilePath, envId) {
|
|
522
|
+
const env = envId ?? "unknown";
|
|
523
|
+
const docOrigin = source === "file" && userFilePath ? `${userFilePath} (environment ${env})` : source === "hardcoded-fallback" ? `the built-in fallback for ${env}` : `assets/environments.json shipped with bulletin-deploy (environment ${env})`;
|
|
524
|
+
const out = {};
|
|
525
|
+
for (const key of Object.keys(envContracts)) out[key] = docOrigin;
|
|
526
|
+
for (const [key, addr] of Object.entries(cliContracts ?? {})) out[key] = `the --contract flag or contracts option (${key}=${addr})`;
|
|
527
|
+
return out;
|
|
528
|
+
}
|
|
521
529
|
function isValidDoc(value) {
|
|
522
530
|
if (!value || typeof value !== "object") return false;
|
|
523
531
|
const v = value;
|
|
@@ -594,13 +602,13 @@ async function loadEnvironments(opts = {}) {
|
|
|
594
602
|
for (const env of merged.environments) {
|
|
595
603
|
if (env.contracts && Object.keys(env.contracts).length > 0) {
|
|
596
604
|
try {
|
|
597
|
-
validateContractAddresses(env.contracts, env.id);
|
|
605
|
+
validateContractAddresses(env.contracts, env.id, describeContractSources(env.contracts, void 0, "file", userFilePath, env.id));
|
|
598
606
|
} catch (err) {
|
|
599
607
|
warn(`bulletin-deploy: Warning: ${err?.message ?? err}`);
|
|
600
608
|
}
|
|
601
609
|
}
|
|
602
610
|
}
|
|
603
|
-
return { doc: merged, source: "file" };
|
|
611
|
+
return { doc: merged, source: "file", userFilePath };
|
|
604
612
|
}
|
|
605
613
|
const bundled = await readBundled(bundledPath, capture);
|
|
606
614
|
if (bundled) return { doc: bundled, source: "bundled" };
|
|
@@ -722,6 +730,7 @@ export {
|
|
|
722
730
|
defaultBundledPath,
|
|
723
731
|
isValidContractAddress,
|
|
724
732
|
validateContractAddresses,
|
|
733
|
+
describeContractSources,
|
|
725
734
|
deepMergeEnvironments,
|
|
726
735
|
loadEnvironments,
|
|
727
736
|
resolveEndpoints,
|