bulletin-deploy 0.6.0-rc.9 → 0.6.0

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 CHANGED
@@ -6,18 +6,12 @@ Deploy static sites and apps to the Polkadot Triangle network with decentralized
6
6
 
7
7
  ```bash
8
8
  npm install -g bulletin-deploy
9
- bulletin-deploy my-app00.dot
10
- ```
11
-
12
- bulletin-deploy auto-detects your framework, runs the build, and deploys. Your site is live at `https://my-app00.dot.li`
13
-
14
- You can also deploy a pre-built directory:
15
-
16
- ```bash
17
- npm run build
9
+ # Build your app (e.g. npm run build)
18
10
  bulletin-deploy ./dist my-app00.dot
19
11
  ```
20
12
 
13
+ Your site is live at `https://my-app00.dot.li`
14
+
21
15
  ## Prerequisites
22
16
 
23
17
  - **Node.js 22+**
@@ -38,58 +32,53 @@ ipfs init
38
32
  ## CLI Usage
39
33
 
40
34
  ```bash
41
- bulletin-deploy <domain.dot> # Auto-detect, build, deploy
42
- bulletin-deploy <build-dir> <domain.dot> # Deploy pre-built directory
43
- bulletin-deploy --build-only # Build only, print output dir
44
- bulletin-deploy --dry-run <domain.dot> # Show upload plan without deploying
35
+ bulletin-deploy <build-dir> <domain.dot>
45
36
  ```
46
37
 
47
- ### Options
38
+ Examples:
48
39
 
40
+ ```bash
41
+ # Basic deploy
42
+ bulletin-deploy ./dist my-app00.dot
43
+
44
+ # Custom RPC endpoint
45
+ bulletin-deploy --rpc wss://custom-bulletin.example.com ./dist my-app00.dot
46
+
47
+ # Deploy and publish to the Playground remix registry
48
+ bulletin-deploy --playground ./dist my-app00.dot
49
49
  ```
50
- Build:
51
- --build-cmd "..." Override detected build command
52
- --build-dir ./out Override detected output directory
53
- --no-build Skip build (require build dir as first arg)
54
- --build-only Build only, print output dir to stdout
55
- --dry-run Show what would be uploaded without deploying
56
- --print-cache-paths Print detected cache paths for CI caching
57
-
58
- Deploy:
59
- --rpc wss://... Bulletin RPC (or set BULLETIN_RPC env var)
60
- --help Show help
50
+
51
+ ### All options
52
+
53
+ ```
54
+ Options:
55
+ --rpc wss://... Bulletin RPC (or set BULLETIN_RPC env var)
56
+ --mnemonic "..." DotNS owner mnemonic (or set MNEMONIC env var)
57
+ --playground Publish to the Playground remix registry
58
+ --pool-size N Number of pool accounts (default: 10)
59
+ --help Show help
61
60
  ```
62
61
 
63
- ### Build detection order
62
+ ### Playground registry
64
63
 
65
- bulletin-deploy auto-detects your project setup:
64
+ By default, deploys only upload to Bulletin storage and register the DotNS domain. The **Playground remix registry** is an on-chain app directory that makes your deploy visible in [Polkadot Playground](https://playground.polkadot.cloud).
66
65
 
67
- 1. **Package manager**: `pnpm-lock.yaml` → pnpm, `bun.lockb`/`bun.lock` → bun, `yarn.lock` → yarn, `package-lock.json` → npm
68
- 2. **Build command**: `Makefile` with `build` target → `make build`, otherwise `package.json` `build` script → `<pm> run build`
69
- 3. **Output directory**: framework config (`vite.config.*` → `dist/`, `next.config.*` → `out/`), or probes `dist/`, `out/`, `build/`
66
+ To publish to it, pass `--playground`:
70
67
 
71
- ### Exit codes
68
+ ```bash
69
+ bulletin-deploy --playground ./dist my-app.dot
70
+ ```
72
71
 
73
- | Code | Meaning | Retryable |
74
- |------|---------|-----------|
75
- | 0 | Success | — |
76
- | 1 | Deploy failure (transient) | Yes |
77
- | 2 | Build failure | No |
78
- | 3 | Configuration error | No |
72
+ This requires `cdm.json` in your project root (shipped with bulletin-deploy) and a git remote origin.
79
73
 
80
74
  ## GitHub Actions
81
75
 
82
76
  1. Copy `workflows/deploy-on-pr.yml` to your repo's `.github/workflows/` directory
83
- 2. Add your `DOTNS_MNEMONIC` secret in repo settings
84
- 3. Push and watch the deploy — no other configuration needed
77
+ 2. Customize the **Build** step for your framework (Vite, Next.js, etc.)
78
+ 3. Push and watch the deploy
85
79
 
86
80
  The template workflow:
87
- - Deploys on push to main and on PRs, with `workflow_dispatch` support
88
- - Auto-detects your framework, package manager, and build output directory
89
- - Uses three cache layers to speed up repeat deploys:
90
- - **Node modules cache** via `actions/setup-node` with `cache: 'npm'`
91
- - **Build artifacts cache** keyed on lockfile hash (paths detected by `--print-cache-paths`)
92
- - **Deploy manifest cache** (`.bulletin-deploy-cache`) keyed on branch + SHA for incremental uploads
81
+ - Deploys on push to main and on PRs
93
82
  - Uses `nick-fields/retry@v3` for automatic retries on transient failures
94
83
  - Posts a comment on PRs with the live URL
95
84
  - Generates domain names as `<repo>-<branch>00.dot`
@@ -103,20 +92,41 @@ const result = await deploy("./dist", "my-app00.dot");
103
92
  console.log(result.cid, result.domainName);
104
93
  ```
105
94
 
95
+ ## Domain Names and Proof of Personhood
96
+
97
+ DotNS domain names are classified by the PopOracle contract on Asset Hub. The classification determines what level of **Proof of Personhood (PoP)** is required to register:
98
+
99
+ | Domain pattern | Example | Required PoP |
100
+ |---|---|---|
101
+ | Name with trailing digits | `my-app00.dot` | **None** — open to all |
102
+ | Base name (no trailing digits) | `my-app.dot` | **Full** — requires `ProofOfPersonhoodFull` |
103
+
104
+ On **testnets** (Paseo, Westend, local devnets), bulletin-deploy automatically self-grants `ProofOfPersonhoodFull` before registration — no configuration needed. Both base names and names with trailing digits just work:
105
+
106
+ ```bash
107
+ bulletin-deploy ./dist my-app.dot # base name — auto-grants Full PoP
108
+ bulletin-deploy ./dist my-app00.dot # trailing digits — no PoP needed
109
+ ```
110
+
111
+ On **mainnet** (Polkadot Hub, Kusama Hub), PoP cannot be self-granted. You must have a verified account. Set `DOTNS_STATUS=none` explicitly or leave it unset (mainnet defaults to `none`).
112
+
113
+ If you see **"Requires Full Personhood verification"**, the deploy will fail early with an actionable error message before any gas is spent on commitment transactions.
114
+
106
115
  ## Environment Variables
107
116
 
108
117
  | Variable | Default | Description |
109
118
  |---|---|---|
110
119
  | `BULLETIN_RPC` | `wss://paseo-bulletin-rpc.polkadot.io` | Bulletin chain WebSocket RPC |
111
120
  | `BULLETIN_DEPLOY_TELEMETRY` | `1` (enabled) | Set to `0` to disable Sentry telemetry |
121
+ | `DOTNS_STATUS` | `full` (testnet) / `none` (mainnet) | PoP level to self-grant before registration: `none`, `lite`, or `full` |
112
122
  | `IPFS_CID` | _(none)_ | Skip storage, use pre-existing CID |
113
123
 
114
124
  ## How It Works
115
125
 
116
126
  ```
117
- Source ──> Build ──> Build output ──> IPFS merkleize ──> Classify ──> Upload delta ──> DotNS ──> Registry
118
- code auto ./dist ipfs add manifest Bulletin Asset Hub CDM
119
- detect compare Storage Registry
127
+ Build output ──> IPFS merkleize ──> CAR file ──> Chunk upload ──> DotNS
128
+ ./dist ipfs add .car Bulletin Asset Hub
129
+ Storage Registry
120
130
  ```
121
131
 
122
132
  1. **Merkleize** your build directory with IPFS to produce a content-addressed CAR file
@@ -140,16 +150,6 @@ Instead of using a single account for all storage transactions, bulletin-deploy
140
150
 
141
151
  When a pool account's authorization drops below thresholds (50 transactions or 50MB), bulletin-deploy automatically tops it up by submitting an `authorize_account` transaction from Alice.
142
152
 
143
- ## Incremental Upload
144
-
145
- On repeat deploys, bulletin-deploy only uploads content that changed. A deploy manifest (`.bulletin-deploy-cache`) tracks which files and chunks are already on-chain.
146
-
147
- - **First deploy**: uploads everything, writes the manifest
148
- - **Subsequent deploys**: compares file CIDs against the manifest, uploads only new/changed files
149
- - **Typical savings**: 80-95% reduction in upload size and transactions
150
-
151
- Use `--dry-run` to preview what would be uploaded before deploying.
152
-
153
153
  ## Telemetry
154
154
 
155
155
  Sentry telemetry is enabled by default for deploy observability. Set `BULLETIN_DEPLOY_TELEMETRY=0` to disable.
@@ -167,6 +167,7 @@ Dashboard: https://polkadot-community-foundation.sentry.io/dashboards/92523/
167
167
 
168
168
  | Error | Solution |
169
169
  |---|---|
170
+ | `Requires Full Personhood verification` | Auto-handled on testnets (v0.5.4+). On mainnet, your account needs verified PoP status. |
170
171
  | `Payment` or authorization error | Pool account needs storage authorization — auto-authorization should handle this |
171
172
  | `Stale` or dropped from best chain | Bulletin chain reorg. Automatic retry handles this. |
172
173
  | `IPFS CLI not installed` | Install Kubo: `brew install ipfs && ipfs init` |
@@ -1,217 +1,69 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // build.js and manifest.js are lightweight (no @dotdm/cdm dependency),
4
- // so we can import them eagerly. deploy.js and pool.js are loaded lazily
5
- // so that --help and --print-cache-paths work without @dotdm/cdm installed.
6
- import { detectFramework, detectCachePaths } from "../dist/build.js";
3
+ import { deploy, DEFAULT_BULLETIN_RPC, DEFAULT_POOL_SIZE } from "../dist/deploy.js";
4
+ import { bootstrapPool } from "../dist/pool.js";
7
5
  import * as fs from "fs";
8
- import * as path from "path";
9
- import * as os from "os";
10
6
 
11
7
  const args = process.argv.slice(2);
12
8
 
13
9
  const flags = {};
14
10
  const positional = [];
15
11
  for (let i = 0; i < args.length; i++) {
16
- const arg = args[i];
17
- if (arg === "--bootstrap") { flags.bootstrap = true; }
18
- else if (arg === "--pool-size") { flags.poolSize = parseInt(args[++i], 10); }
19
- else if (arg === "--mnemonic") { flags.mnemonic = args[++i]; }
20
- else if (arg === "--rpc") { flags.rpc = args[++i]; }
21
- else if (arg === "--build-cmd") { flags.buildCmd = args[++i]; }
22
- else if (arg === "--build-dir") { flags.buildDir = args[++i]; }
23
- else if (arg === "--no-build") { flags.noBuild = true; }
24
- else if (arg === "--build-only") { flags.buildOnly = true; }
25
- else if (arg === "--print-cache-paths") { flags.printCachePaths = true; }
26
- else if (arg === "--dry-run") { flags.dryRun = true; }
27
- else if (arg === "--registry") { flags.registry = true; }
28
- else if (arg === "--help" || arg === "-h") { flags.help = true; }
29
- else { positional.push(arg); }
12
+ if (args[i] === "--bootstrap") { flags.bootstrap = true; }
13
+ else if (args[i] === "--pool-size") { flags.poolSize = parseInt(args[++i], 10); }
14
+ else if (args[i] === "--mnemonic") { flags.mnemonic = args[++i]; }
15
+ else if (args[i] === "--rpc") { flags.rpc = args[++i]; }
16
+ else if (args[i] === "--password") { flags.password = args[++i]; }
17
+ else if (args[i] === "--playground") { flags.playground = true; }
18
+ else if (args[i] === "--help" || args[i] === "-h") { flags.help = true; }
19
+ else { positional.push(args[i]); }
30
20
  }
31
21
 
32
- if (flags.help || (positional.length === 0 && !flags.bootstrap && !flags.printCachePaths && !flags.buildOnly)) {
22
+ if (flags.help || (positional.length === 0 && !flags.bootstrap)) {
33
23
  console.log(`Usage:
34
- bulletin-deploy <domain.dot> Auto-build and deploy
35
- bulletin-deploy <build-dir> <domain.dot> Deploy a pre-built directory
24
+ bulletin-deploy <build-dir> <domain.dot> Deploy an app
36
25
  bulletin-deploy --bootstrap Initialize pool accounts
37
26
 
38
27
  Options:
39
- --build-cmd "..." Override build command
40
- --build-dir ./out Override output directory
41
- --no-build Skip the build step (use positional arg as build dir)
42
- --build-only Build only, print output dir to stdout, then exit
43
- --print-cache-paths Print detected cache paths and exit
44
- --dry-run Show upload plan without deploying
45
- --registry Publish to playground registry (only needed on metadata change)
46
28
  --mnemonic "..." DotNS owner mnemonic (or set MNEMONIC env var)
47
29
  --rpc wss://... Bulletin RPC (or set BULLETIN_RPC env var)
48
30
  --pool-size N Number of pool accounts (default: 10)
31
+ --password "..." Encrypt SPA content (users will be prompted to decrypt)
32
+ --playground Publish to the playground remix registry
49
33
  --help Show this help`);
50
34
  process.exit(0);
51
35
  }
52
36
 
53
- if (flags.rpc) process.env.BULLETIN_RPC = flags.rpc;
54
- if (flags.poolSize) process.env.BULLETIN_POOL_SIZE = String(flags.poolSize);
55
- if (flags.mnemonic) process.env.MNEMONIC = flags.mnemonic;
56
-
57
- const projectDir = process.cwd();
58
-
59
- // --print-cache-paths: detect and print, then exit (no heavy deps needed)
60
- if (flags.printCachePaths) {
61
- const framework = detectFramework(projectDir);
62
- const cachePaths = detectCachePaths(framework);
63
- for (const p of cachePaths) {
64
- console.log(p);
65
- }
66
- process.exit(0);
67
- }
68
-
69
- // Lazy-load heavy modules that require @dotdm/cdm; run in parallel
70
- const [
71
- { deploy, merkleize, chunk, measureBuildOutput },
72
- { runBuild },
73
- { readManifest, classifyWithManifest, classifyFile, formatDryRunReport },
74
- { bootstrapPool },
75
- ] = await Promise.all([
76
- import("../dist/deploy.js"),
77
- import("../dist/build.js"),
78
- import("../dist/manifest.js"),
79
- import("../dist/pool.js"),
80
- ]);
81
-
82
37
  try {
83
38
  if (flags.bootstrap) {
84
- const rpc = process.env.BULLETIN_RPC || "wss://paseo-bulletin-rpc.polkadot.io";
85
- const poolSize = parseInt(process.env.BULLETIN_POOL_SIZE || "10", 10);
86
- await bootstrapPool(rpc, poolSize);
87
- process.exit(0);
88
- }
89
-
90
- // --build-only: run build, print output dir, exit
91
- if (flags.buildOnly) {
92
- const result = await runBuild(projectDir, {
93
- buildCmd: flags.buildCmd,
94
- buildDir: flags.buildDir,
95
- });
96
- console.log(path.resolve(projectDir, result.outputDir));
97
- process.exit(0);
98
- }
99
-
100
- // Determine build dir and domain from positional args
101
- let buildDir;
102
- let domain;
103
-
104
- const [firstArg, secondArg] = positional;
105
-
106
- if (firstArg && fs.existsSync(firstArg)) {
107
- // Backward-compat: first arg is an existing path — treat as build dir
108
- buildDir = firstArg;
109
- domain = secondArg;
39
+ const rpc = flags.rpc ?? process.env.BULLETIN_RPC ?? DEFAULT_BULLETIN_RPC;
40
+ const poolSize = flags.poolSize ?? parseInt(process.env.BULLETIN_POOL_SIZE ?? String(DEFAULT_POOL_SIZE), 10);
41
+ await bootstrapPool(rpc, poolSize, flags.mnemonic);
110
42
  } else {
111
- domain = firstArg;
112
- buildDir = null;
113
- }
114
-
115
- if (!domain) {
116
- console.error("Error: domain required (e.g. my-app.dot)");
117
- process.exit(3);
118
- }
119
-
120
- // Build step (unless --no-build or buildDir already provided from positional)
121
- let detectedFramework;
122
- if (!buildDir && !flags.noBuild) {
123
- console.log("\nBuilding...");
124
- const buildResult = await runBuild(projectDir, {
125
- buildCmd: flags.buildCmd,
126
- buildDir: flags.buildDir,
43
+ const [buildDir, domain] = positional;
44
+ if (!buildDir) { console.error("Error: build directory required"); process.exit(1); }
45
+ if (!domain) { console.error("Error: domain required (e.g. my-app.dot)"); process.exit(1); }
46
+ if (!fs.existsSync(buildDir)) { console.error(`Error: ${buildDir} does not exist`); process.exit(1); }
47
+
48
+ const result = await deploy(buildDir, domain, {
49
+ playground: flags.playground,
50
+ mnemonic: flags.mnemonic,
51
+ rpc: flags.rpc,
52
+ poolSize: flags.poolSize,
53
+ password: flags.password,
127
54
  });
128
- buildDir = path.resolve(projectDir, buildResult.outputDir);
129
- detectedFramework = buildResult.framework?.name;
130
- console.log(` Output: ${buildDir} (${buildResult.durationMs}ms)`);
131
- } else if (flags.noBuild && !buildDir) {
132
- if (flags.buildDir) {
133
- buildDir = flags.buildDir;
134
- } else {
135
- console.error("Error: --no-build requires a build directory (pass as first arg or --build-dir)");
136
- process.exit(3);
137
- }
138
- }
139
-
140
- if (!fs.existsSync(buildDir)) {
141
- console.error(`Error: build directory not found: ${buildDir}`);
142
- process.exit(3);
143
- }
144
-
145
- // --dry-run: show upload plan without deploying
146
- if (flags.dryRun) {
147
- const { execSync } = await import("child_process");
148
- const { createCID } = await import("../dist/deploy.js");
149
-
150
- // Merkleize + get per-file CIDs (matches storeDirectory's flow)
151
- const ipfsCid = execSync(`ipfs add -Q -r --cid-version=1 --raw-leaves --pin=false "${buildDir}"`, { encoding: "utf-8" }).trim();
152
- const addOutput = execSync(`ipfs add -rn --cid-version=1 --raw-leaves --pin=false "${buildDir}"`, { encoding: "utf-8" });
153
- const baseName = path.basename(buildDir);
154
- const fileCids = new Map();
155
- for (const line of addOutput.trim().split("\n")) {
156
- const m = line.match(/^added\s+(\S+)\s+(.+)$/);
157
- if (!m) continue;
158
- const rel = m[2].startsWith(baseName + "/") ? m[2].slice(baseName.length + 1) : m[2];
159
- if (rel !== baseName) fileCids.set(rel, m[1]);
160
- }
161
-
162
- const manifestPath = path.join(path.dirname(buildDir), ".bulletin-deploy-cache");
163
- const manifest = readManifest(manifestPath);
164
- const buildOutput = measureBuildOutput(buildDir);
165
-
166
- const currentFiles = buildOutput.files.map(f => ({ path: f.path, cid: fileCids.get(f.path) || ipfsCid, size: f.size }));
167
55
 
168
- let classification;
169
- if (manifest) {
170
- classification = classifyWithManifest(currentFiles, manifest);
171
- } else {
172
- const stable = currentFiles.filter(f => classifyFile(f.path) === "stable");
173
- const volatile = currentFiles
174
- .filter(f => classifyFile(f.path) === "volatile")
175
- .map(f => ({ ...f, previousCid: null }));
176
- classification = { stable, volatile, hitRate: stable.length / (currentFiles.length || 1), source: "heuristic" };
56
+ const output = process.env.GITHUB_OUTPUT;
57
+ if (output) {
58
+ fs.appendFileSync(output, `cid=${result.cid}\n`);
59
+ fs.appendFileSync(output, `domain=${result.domainName}\n`);
177
60
  }
178
61
 
179
- // Estimate chunks from total file sizes
180
- const totalBytes = buildOutput.files.reduce((s, f) => s + f.size, 0);
181
- const totalChunks = Math.ceil(totalBytes / (1024 * 1024));
182
- const volatileBytes = classification.volatile.reduce((s, f) => s + f.size, 0);
183
- const newChunks = manifest ? Math.max(1, Math.ceil(volatileBytes / (1024 * 1024))) : totalChunks;
184
-
185
- const report = formatDryRunReport(classification, {
186
- manifestPath: manifest ? manifestPath : null,
187
- lastDeploy: manifest ? manifest.deployed_at : null,
188
- totalChunks,
189
- newChunks,
190
- });
191
- console.log(report);
192
- process.exit(0);
193
- }
194
-
195
- const result = await deploy(buildDir, domain, { registry: flags.registry ?? false, framework: detectedFramework });
196
-
197
- const output = process.env.GITHUB_OUTPUT;
198
- if (output) {
199
- fs.appendFileSync(output, `cid=${result.cid}\n`);
200
- fs.appendFileSync(output, `domain=${result.domainName}\n`);
62
+ console.log(`CID: ${result.cid}`);
63
+ console.log(`Domain: ${result.domainName}`);
201
64
  }
202
-
203
- console.log(`CID: ${result.cid}`);
204
- console.log(`Domain: ${result.domainName}`);
205
65
  process.exit(0);
206
-
207
66
  } catch (error) {
208
- const exitCode = error.exitCode ?? 1;
209
- if (exitCode === 2) {
210
- console.error("Build failed:", error.message);
211
- } else if (exitCode === 3) {
212
- console.error("Config error:", error.message);
213
- } else {
214
- console.error("Deployment failed:", error.message);
215
- }
216
- process.exit(exitCode);
67
+ console.error("Deployment failed:", error.message);
68
+ process.exit(1);
217
69
  }
package/cdm.json CHANGED
@@ -13,8 +13,8 @@
13
13
  "contracts": {
14
14
  "acc2c3b5e912b762": {
15
15
  "@example/playground-registry": {
16
- "version": 2,
17
- "address": "0x7D97a3E87c0C2fe921E471D076b95975886CEAA8",
16
+ "version": 3,
17
+ "address": "0xF8304E5C17769A53E012f39c6990cC8a7AaBC6A5",
18
18
  "abi": [
19
19
  {
20
20
  "type": "constructor",
@@ -39,35 +39,58 @@
39
39
  },
40
40
  {
41
41
  "type": "function",
42
- "name": "getMetadataUri",
42
+ "name": "getAppCount",
43
+ "inputs": [],
44
+ "outputs": [
45
+ {
46
+ "name": "",
47
+ "type": "uint32"
48
+ }
49
+ ],
50
+ "stateMutability": "view"
51
+ },
52
+ {
53
+ "type": "function",
54
+ "name": "getDomainAt",
43
55
  "inputs": [
44
56
  {
45
- "name": "domain",
57
+ "name": "index",
58
+ "type": "uint32"
59
+ }
60
+ ],
61
+ "outputs": [
62
+ {
63
+ "name": "",
46
64
  "type": "string"
47
65
  }
48
66
  ],
67
+ "stateMutability": "view"
68
+ },
69
+ {
70
+ "type": "function",
71
+ "name": "getOwnerAppCount",
72
+ "inputs": [
73
+ {
74
+ "name": "owner",
75
+ "type": "address"
76
+ }
77
+ ],
49
78
  "outputs": [
50
79
  {
51
80
  "name": "",
52
- "type": "tuple",
53
- "components": [
54
- {
55
- "name": "isSome",
56
- "type": "bool"
57
- },
58
- {
59
- "name": "value",
60
- "type": "string"
61
- }
62
- ]
81
+ "type": "uint32"
63
82
  }
64
83
  ],
65
84
  "stateMutability": "view"
66
85
  },
67
86
  {
68
87
  "type": "function",
69
- "name": "getDomainAt",
88
+ "name": "getOwnerDomainAt",
70
89
  "inputs": [
90
+ {
91
+ "name": "owner",
92
+ "type": "address"
93
+ },
71
94
  {
72
95
  "name": "index",
73
96
  "type": "uint32"
@@ -83,7 +106,7 @@
83
106
  },
84
107
  {
85
108
  "type": "function",
86
- "name": "getOwner",
109
+ "name": "getMetadataUri",
87
110
  "inputs": [
88
111
  {
89
112
  "name": "domain",
@@ -93,25 +116,40 @@
93
116
  "outputs": [
94
117
  {
95
118
  "name": "",
96
- "type": "address"
119
+ "type": "tuple",
120
+ "components": [
121
+ {
122
+ "name": "isSome",
123
+ "type": "bool"
124
+ },
125
+ {
126
+ "name": "value",
127
+ "type": "string"
128
+ }
129
+ ]
97
130
  }
98
131
  ],
99
132
  "stateMutability": "view"
100
133
  },
101
134
  {
102
135
  "type": "function",
103
- "name": "getAppCount",
104
- "inputs": [],
136
+ "name": "getOwner",
137
+ "inputs": [
138
+ {
139
+ "name": "domain",
140
+ "type": "string"
141
+ }
142
+ ],
105
143
  "outputs": [
106
144
  {
107
145
  "name": "",
108
- "type": "uint32"
146
+ "type": "address"
109
147
  }
110
148
  ],
111
149
  "stateMutability": "view"
112
150
  }
113
151
  ],
114
- "metadataCid": "bafk2bzacecrjrmrgumcww7oc23rllfscbxpd2lxc6p2svb26c6e5tjvmr565s"
152
+ "metadataCid": "bafk2bzacebkch7cuoi77j5vkrkoplax4urywwga7ijamtd3pntv7xjgabhtgs"
115
153
  }
116
154
  }
117
155
  }
@@ -70,11 +70,6 @@ async function ensureAuthorized(api, poolAccount, bulletinRpc) {
70
70
  try {
71
71
  const keyring = new Keyring({ type: "sr25519" });
72
72
  const alice = keyring.addFromUri("//Alice");
73
- const aliceAccount = await aliceApi.query.System.Account.getValue(alice.address);
74
- const aliceBalance = BigInt(aliceAccount.data.free);
75
- if (aliceBalance < 10000000000n) {
76
- throw new Error(`Alice has insufficient balance on Bulletin for authorization tx fees. Current: ${(Number(aliceBalance) / 1e12).toFixed(4)} PAS`);
77
- }
78
73
  const aliceSigner = getPolkadotSigner(alice.publicKey, "Sr25519", (data) => alice.sign(data));
79
74
  const tx = aliceApi.tx.TransactionStorage.authorize_account({
80
75
  who: poolAccount.address,