rdx-cli 0.1.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.
@@ -0,0 +1,2089 @@
1
+ import { ConfigProvider, Console, Data, Effect, Layer, Option, Schema } from "effect";
2
+ import { GatewayApiClient, GetFungibleBalance, GetNonFungibleBalanceService } from "@radix-effects/gateway";
3
+ import { Convert, PublicKey, RadixEngineToolkit, Signature, SignatureWithPublicKey, TransactionV2Builder } from "@steleaio/radix-engine-toolkit";
4
+ import { basename, dirname, join, parse, resolve } from "node:path";
5
+ import { FileSystem } from "@effect/platform";
6
+ import { NodeFileSystem } from "@effect/platform-node";
7
+ import { ed25519 } from "@noble/curves/ed25519";
8
+ import { Args, Command, Options } from "@effect/cli";
9
+ import { homedir } from "node:os";
10
+ import { createHash } from "node:crypto";
11
+
12
+ //#region src/json.ts
13
+ const JsonValueSchema = Schema.Union(Schema.Null, Schema.Boolean, Schema.JsonNumber, Schema.String, Schema.Array(Schema.suspend(() => JsonValueSchema)), Schema.Record({
14
+ key: Schema.String,
15
+ value: Schema.suspend(() => JsonValueSchema)
16
+ }));
17
+ const JsonStringSchema = Schema.parseJson(JsonValueSchema, { space: 2 });
18
+ const isBigNumberLike = (value) => typeof value === "object" && value !== null && "isBigNumber" in value && typeof value.toString === "function";
19
+ const toJsonValue = (value) => {
20
+ if (value === void 0) return null;
21
+ if (value === null || typeof value === "boolean" || typeof value === "string") return value;
22
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
23
+ if (typeof value === "bigint" || isBigNumberLike(value)) return value.toString();
24
+ if (Array.isArray(value)) return value.map(toJsonValue);
25
+ if (typeof value === "object") {
26
+ if (typeof value.toJSON === "function") return toJsonValue(value.toJSON());
27
+ return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0).map(([key, entry]) => [key, toJsonValue(entry)]));
28
+ }
29
+ return String(value);
30
+ };
31
+ const renderJson = (value) => Schema.encodeUnknownSync(JsonStringSchema)(toJsonValue(value));
32
+
33
+ //#endregion
34
+ //#region src/schemas.ts
35
+ const PLACEHOLDER_PUBLIC_KEY_HEX = "<replace-with-ed25519-public-key-hex>";
36
+ const PLACEHOLDER_SIGNATURE_HEX = "<replace-with-ed25519-signature-hex>";
37
+ const NetworkSchema = Schema.Literal("mainnet", "stokenet").pipe(Schema.brand("Network"));
38
+ const ArtifactScopeSchema = Schema.Literal("local", "global").pipe(Schema.brand("ArtifactScope"));
39
+ const OutputFormatSchema = Schema.Literal("json", "text").pipe(Schema.brand("OutputFormat"));
40
+ const HexStringSchema = Schema.String.pipe(Schema.pattern(/^[0-9a-fA-F]+$/));
41
+ const Ed25519PublicKeyHexSchema = HexStringSchema.pipe(Schema.length(64));
42
+ const Ed25519SignatureHexSchema = HexStringSchema.pipe(Schema.length(128));
43
+ const SubintentIdSchema = Schema.String.pipe(Schema.pattern(/^[A-Za-z][A-Za-z0-9_-]{0,63}$/));
44
+ const PublicKeySchema = Schema.Struct({
45
+ curve: Schema.Literal("Ed25519"),
46
+ hex: Ed25519PublicKeyHexSchema
47
+ });
48
+ const PublicKeyOrPlaceholderSchema = Schema.Struct({
49
+ curve: Schema.Literal("Ed25519"),
50
+ hex: Schema.Union(Ed25519PublicKeyHexSchema, Schema.Literal(PLACEHOLDER_PUBLIC_KEY_HEX))
51
+ });
52
+ const SignatureValueSchema = Schema.Struct({
53
+ curve: Schema.Literal("Ed25519"),
54
+ hex: Ed25519SignatureHexSchema
55
+ });
56
+ const SignatureValueOrPlaceholderSchema = Schema.Struct({
57
+ curve: Schema.Literal("Ed25519"),
58
+ hex: Schema.Union(Ed25519SignatureHexSchema, Schema.Literal(PLACEHOLDER_SIGNATURE_HEX))
59
+ });
60
+ const SigningScopeSchema = Schema.Union(Schema.Struct({ kind: Schema.Literal("rootIntent") }), Schema.Struct({
61
+ kind: Schema.Literal("subintent"),
62
+ subintentId: SubintentIdSchema
63
+ }), Schema.Struct({ kind: Schema.Literal("notarySignatory") }), Schema.Struct({ kind: Schema.Literal("notary") }));
64
+ const HashSchema = Schema.Struct({
65
+ id: Schema.NullOr(Schema.String),
66
+ hex: HexStringSchema
67
+ });
68
+ const SigningRequestSchema = Schema.Struct({
69
+ type: Schema.Literal("signingRequest"),
70
+ version: Schema.Literal(1),
71
+ transactionId: Schema.NonEmptyString,
72
+ scope: SigningScopeSchema,
73
+ account: Schema.NullOr(Schema.NonEmptyString),
74
+ hash: HashSchema,
75
+ signingRequestPath: Schema.optional(Schema.String)
76
+ });
77
+ const SignatureTemplateSchema = Schema.Struct({
78
+ type: Schema.Literal("signatureTemplate"),
79
+ version: Schema.Literal(1),
80
+ transactionId: Schema.NonEmptyString,
81
+ scope: SigningScopeSchema,
82
+ account: Schema.NullOr(Schema.NonEmptyString),
83
+ hash: HashSchema,
84
+ signingRequestPath: Schema.optional(Schema.String),
85
+ publicKey: PublicKeyOrPlaceholderSchema,
86
+ signature: SignatureValueOrPlaceholderSchema
87
+ });
88
+ const SignatureEntrySchema = Schema.Struct({
89
+ scope: SigningScopeSchema,
90
+ account: Schema.NullOr(Schema.NonEmptyString),
91
+ hash: HashSchema,
92
+ signingRequestPath: Schema.optional(Schema.String),
93
+ publicKey: PublicKeySchema.pipe(Schema.filter((value) => value.hex !== PLACEHOLDER_PUBLIC_KEY_HEX, { message: () => "Replace the public key placeholder before importing signatures" })),
94
+ signature: SignatureValueSchema.pipe(Schema.filter((value) => value.hex !== PLACEHOLDER_SIGNATURE_HEX, { message: () => "Replace the signature placeholder before importing signatures" }))
95
+ });
96
+ const SignatureFileSchema = Schema.Struct({
97
+ type: Schema.Literal("signatureFile"),
98
+ version: Schema.Literal(1),
99
+ transactionId: Schema.NonEmptyString,
100
+ signatures: Schema.Array(SignatureEntrySchema)
101
+ });
102
+ const BatchSignatureFileSchema = Schema.Struct({
103
+ type: Schema.Literal("batchSignatureFile"),
104
+ version: Schema.Literal(1),
105
+ signatures: Schema.NonEmptyArray(SignatureFileSchema)
106
+ });
107
+ const SubintentsFileSchema = Schema.Struct({
108
+ type: Schema.Literal("subintents"),
109
+ version: Schema.Literal(1),
110
+ subintents: Schema.Record({
111
+ key: Schema.String,
112
+ value: Schema.Struct({ manifest: Schema.NonEmptyString })
113
+ }).pipe(Schema.filter((subintents) => Object.keys(subintents).every((key) => /^[A-Za-z][A-Za-z0-9_-]{0,63}$/.test(key)), { message: () => "Subintent IDs must be conservative identifiers" }))
114
+ });
115
+ const NotaryFileSchema = Schema.Struct({
116
+ type: Schema.Literal("notary"),
117
+ version: Schema.Literal(1),
118
+ publicKey: PublicKeySchema,
119
+ notaryIsSignatory: Schema.optional(Schema.Boolean)
120
+ });
121
+ const ArtifactStatusSchema = Schema.Union(Schema.Literal("prepared"), Schema.Literal("notarized"), Schema.Literal("submitted"));
122
+ const AuthorizationAnalysisSchema = Schema.Struct({
123
+ rootIntent: Schema.Array(Schema.String),
124
+ subintents: Schema.Record({
125
+ key: Schema.String,
126
+ value: Schema.Array(Schema.String)
127
+ })
128
+ });
129
+ const PreparedTransactionSchema = Schema.Struct({
130
+ type: Schema.Literal("preparedTransaction"),
131
+ version: Schema.Literal(1),
132
+ transactionId: Schema.NonEmptyString,
133
+ network: NetworkSchema,
134
+ intentHash: HashSchema,
135
+ manifestSourceFile: Schema.String,
136
+ transactionIntentPath: Schema.String,
137
+ staticAnalysisPath: Schema.String,
138
+ signingRequests: Schema.Array(Schema.String),
139
+ signatureTemplates: Schema.Array(Schema.String),
140
+ subintentOrder: Schema.Array(Schema.String),
141
+ authorizationAnalysis: AuthorizationAnalysisSchema,
142
+ notaryPublicKey: Schema.optional(PublicKeySchema),
143
+ notaryIsSignatory: Schema.optional(Schema.Boolean)
144
+ });
145
+ const NetworkTransactionStatusSchema = Schema.Struct({
146
+ transactionId: Schema.NonEmptyString,
147
+ status: Schema.String,
148
+ statusDescription: Schema.String,
149
+ errorMessage: Schema.NullOr(Schema.String),
150
+ checkedAt: Schema.String
151
+ });
152
+ const SubmitResultSchema = Schema.Struct({
153
+ type: Schema.Literal("submitResult"),
154
+ version: Schema.Literal(1),
155
+ transactionId: Schema.NonEmptyString,
156
+ networkStatus: NetworkTransactionStatusSchema,
157
+ attempts: Schema.Array(Schema.Struct({
158
+ checkedAt: Schema.String,
159
+ status: Schema.String,
160
+ statusDescription: Schema.String,
161
+ errorMessage: Schema.NullOr(Schema.String)
162
+ }))
163
+ });
164
+ const AccountFungiblesResultSchema = Schema.Struct({
165
+ type: Schema.Literal("commandResult"),
166
+ command: Schema.Literal("account fungibles"),
167
+ result: Schema.Unknown
168
+ });
169
+ const AccountNftsResultSchema = Schema.Struct({
170
+ type: Schema.Literal("commandResult"),
171
+ command: Schema.Literal("account nfts"),
172
+ result: Schema.Unknown
173
+ });
174
+ const AccountShowResultSchema = Schema.Struct({
175
+ type: Schema.Literal("commandResult"),
176
+ command: Schema.Literal("account show"),
177
+ result: Schema.Unknown
178
+ });
179
+ const TransactionHistoryResultSchema = Schema.Struct({
180
+ type: Schema.Literal("commandResult"),
181
+ command: Schema.Literal("tx history"),
182
+ result: Schema.Unknown
183
+ });
184
+ const VirtualAccountDerivationSchema = Schema.Struct({
185
+ network: NetworkSchema,
186
+ derivation: Schema.Literal("virtualAccount"),
187
+ publicKey: PublicKeySchema,
188
+ accountAddress: Schema.String
189
+ });
190
+
191
+ //#endregion
192
+ //#region src/accountReads.ts
193
+ var AccountReadError = class extends Data.TaggedError("AccountReadError") {};
194
+ var InvalidPublicKeyError = class extends Data.TaggedError("InvalidPublicKeyError") {};
195
+ const networkId$1 = (network) => network === "stokenet" ? 2 : 1;
196
+ const gatewayConfigLayer = (config) => Layer.setConfigProvider(ConfigProvider.fromJson({
197
+ NETWORK_ID: networkId$1(config.network),
198
+ ...config.gatewayBaseUrl ? { GATEWAY_URL: config.gatewayBaseUrl } : {}
199
+ }));
200
+ const gatewayApiClientLayer = (config) => GatewayApiClient.Default.pipe(Layer.provide(gatewayConfigLayer(config)));
201
+ const getAccountFungibles = (input) => input.readFungibles(input.accountAddress).pipe(Effect.map((result) => ({
202
+ type: "commandResult",
203
+ command: "account fungibles",
204
+ result: toJsonValue(result)
205
+ })));
206
+ const getAccountNfts = (input) => input.readNfts(input.accountAddress).pipe(Effect.map((result) => ({
207
+ type: "commandResult",
208
+ command: "account nfts",
209
+ result: toJsonValue(result)
210
+ })));
211
+ const gatewayAccountFungibles = (input) => {
212
+ const gatewayLayer = gatewayApiClientLayer(input.config);
213
+ const accountFungiblesLayer = Layer.merge(gatewayLayer, GetFungibleBalance.Default.pipe(Layer.provide(gatewayLayer)));
214
+ return Effect.gen(function* () {
215
+ const status = yield* (yield* GatewayApiClient).status.getCurrent();
216
+ return yield* (yield* GetFungibleBalance)({
217
+ addresses: [input.accountAddress],
218
+ at_ledger_state: { state_version: status.ledger_state.state_version },
219
+ options: { explicit_metadata: ["name", "symbol"] }
220
+ });
221
+ }).pipe(Effect.provide(accountFungiblesLayer), Effect.mapError((reason) => new AccountReadError({
222
+ accountAddress: input.accountAddress,
223
+ reason
224
+ })));
225
+ };
226
+ const gatewayAccountNfts = (input) => {
227
+ const gatewayLayer = gatewayApiClientLayer(input.config);
228
+ const accountNftsLayer = Layer.merge(gatewayLayer, GetNonFungibleBalanceService.Default.pipe(Layer.provide(gatewayLayer)));
229
+ return Effect.gen(function* () {
230
+ const status = yield* (yield* GatewayApiClient).status.getCurrent();
231
+ return yield* (yield* GetNonFungibleBalanceService)({
232
+ addresses: [input.accountAddress],
233
+ at_ledger_state: { state_version: status.ledger_state.state_version }
234
+ });
235
+ }).pipe(Effect.provide(accountNftsLayer), Effect.mapError((reason) => new AccountReadError({
236
+ accountAddress: input.accountAddress,
237
+ reason
238
+ })));
239
+ };
240
+ const gatewayAccountDetails = (input) => Effect.gen(function* () {
241
+ return yield* (yield* GatewayApiClient).state.innerClient.stateEntityDetails({ stateEntityDetailsRequest: {
242
+ addresses: [input.accountAddress],
243
+ aggregation_level: "Vault",
244
+ opt_ins: {
245
+ explicit_metadata: ["name", "description"],
246
+ ancestor_identities: true,
247
+ component_royalty_config: true,
248
+ package_royalty_vault_balance: true
249
+ }
250
+ } });
251
+ }).pipe(Effect.provide(gatewayApiClientLayer(input.config)), Effect.mapError((reason) => new AccountReadError({
252
+ accountAddress: input.accountAddress,
253
+ reason
254
+ })));
255
+ const gatewayAccountHistory = (input) => Effect.gen(function* () {
256
+ return yield* (yield* GatewayApiClient).stream.innerClient.streamTransactions({ streamTransactionsRequest: {
257
+ limit_per_page: input.limit,
258
+ affected_global_entities_filter: [input.accountAddress]
259
+ } });
260
+ }).pipe(Effect.provide(gatewayApiClientLayer(input.config)), Effect.mapError((reason) => new AccountReadError({
261
+ accountAddress: input.accountAddress,
262
+ reason
263
+ })));
264
+ const getAccountDetails = (input) => input.readDetails(input.accountAddress).pipe(Effect.map((result) => ({
265
+ type: "commandResult",
266
+ command: "account show",
267
+ result: toJsonValue(result)
268
+ })));
269
+ const getAccountTransactionHistory = (input) => input.readHistory(input.accountAddress, input.limit).pipe(Effect.map((result) => ({
270
+ type: "commandResult",
271
+ command: "tx history",
272
+ result: toJsonValue(result)
273
+ })));
274
+ const deriveVirtualAccountAddress = (input) => Effect.gen(function* () {
275
+ const publicKey = yield* Schema.decodeUnknown(PublicKeySchema)({
276
+ curve: "Ed25519",
277
+ hex: input.publicKeyHex
278
+ }).pipe(Effect.mapError(() => new InvalidPublicKeyError({
279
+ code: "INVALID_PUBLIC_KEY",
280
+ publicKeyHex: input.publicKeyHex
281
+ })));
282
+ const accountAddress = yield* Effect.tryPromise(async () => RadixEngineToolkit.Derive.virtualAccountAddressFromPublicKey(new PublicKey.Ed25519(publicKey.hex), networkId$1(input.network)));
283
+ return {
284
+ type: "commandResult",
285
+ command: "account derive",
286
+ network: input.network,
287
+ derivation: "virtualAccount",
288
+ publicKey,
289
+ accountAddress
290
+ };
291
+ });
292
+ var AccountReadService = class extends Effect.Service()("AccountReadService", { sync: () => ({
293
+ getAccountDetails,
294
+ getAccountFungibles,
295
+ getAccountNfts,
296
+ getAccountTransactionHistory,
297
+ deriveVirtualAccountAddress,
298
+ gatewayAccountDetails,
299
+ gatewayAccountFungibles,
300
+ gatewayAccountHistory,
301
+ gatewayAccountNfts
302
+ }) }) {};
303
+
304
+ //#endregion
305
+ //#region src/platformIo.ts
306
+ const withNodeFileSystem = (effect) => effect.pipe(Effect.provide(NodeFileSystem.layer));
307
+ const fileExists = (path) => withNodeFileSystem(Effect.gen(function* () {
308
+ return yield* (yield* FileSystem.FileSystem).exists(path);
309
+ }).pipe(Effect.catchAll(() => Effect.succeed(false))));
310
+ const makeDirectory = (path, options, mapError) => withNodeFileSystem(Effect.gen(function* () {
311
+ yield* (yield* FileSystem.FileSystem).makeDirectory(path, options);
312
+ }).pipe(Effect.mapError(mapError)));
313
+ const readDirectory = (path, mapError) => withNodeFileSystem(Effect.gen(function* () {
314
+ return yield* (yield* FileSystem.FileSystem).readDirectory(path);
315
+ }).pipe(Effect.mapError(mapError)));
316
+ const isDirectory = (path, mapError) => withNodeFileSystem(Effect.gen(function* () {
317
+ return (yield* (yield* FileSystem.FileSystem).stat(path)).type === "Directory";
318
+ }).pipe(Effect.mapError(mapError)));
319
+ const readFileString = (path, mapError) => withNodeFileSystem(Effect.gen(function* () {
320
+ return yield* (yield* FileSystem.FileSystem).readFileString(path, "utf8");
321
+ }).pipe(Effect.mapError(mapError)));
322
+ const writeFileString = (path, data, mapError) => withNodeFileSystem(Effect.gen(function* () {
323
+ yield* (yield* FileSystem.FileSystem).writeFileString(path, data);
324
+ }).pipe(Effect.mapError(mapError)));
325
+ const readJsonFile = (path, mapError) => readFileString(path, mapError).pipe(Effect.flatMap((content) => Schema.decodeUnknown(Schema.parseJson())(content).pipe(Effect.mapError(mapError))));
326
+ const writeJsonFile = (path, value, mapError) => writeFileString(path, `${renderJson(value)}\n`, mapError);
327
+
328
+ //#endregion
329
+ //#region src/artifacts.ts
330
+ var ArtifactStoreError = class extends Data.TaggedError("ArtifactStoreError") {};
331
+ const scopeSortKey = (scope) => {
332
+ switch (scope.kind) {
333
+ case "rootIntent": return "0:root";
334
+ case "subintent": return `1:${scope.subintentId}`;
335
+ case "notarySignatory": return "2:notarySignatory";
336
+ case "notary": return "3:notary";
337
+ }
338
+ };
339
+ const signatureIdentity = (entry) => [
340
+ scopeSortKey(entry.scope),
341
+ entry.account ?? "",
342
+ entry.hash.id ?? "",
343
+ entry.hash.hex,
344
+ entry.publicKey.curve,
345
+ entry.publicKey.hex
346
+ ].join("|");
347
+ const sortSignature = (left, right) => signatureIdentity(left).localeCompare(signatureIdentity(right));
348
+ const normalizeSignatures = (input) => {
349
+ const byIdentity = /* @__PURE__ */ new Map();
350
+ const warnings = [];
351
+ let acceptedCount = 0;
352
+ for (const signature of [...input.existing, ...input.imported]) {
353
+ const identity = signatureIdentity(signature);
354
+ const existing = byIdentity.get(identity);
355
+ if (!existing) {
356
+ byIdentity.set(identity, signature);
357
+ if (input.imported.includes(signature)) acceptedCount += 1;
358
+ continue;
359
+ }
360
+ if (existing.signature.hex !== signature.signature.hex) warnings.push(`Ignored differing duplicate signature for ${identity}`);
361
+ }
362
+ return {
363
+ signatureFile: {
364
+ type: "signatureFile",
365
+ version: 1,
366
+ transactionId: input.transactionId,
367
+ signatures: [...byIdentity.values()].sort(sortSignature)
368
+ },
369
+ acceptedCount,
370
+ warnings
371
+ };
372
+ };
373
+ const createTransactionArtifactDirectory = (input) => Effect.gen(function* () {
374
+ yield* makeDirectory(input.artifactRoot, { recursive: true }, (reason) => new ArtifactStoreError({
375
+ path: input.artifactRoot,
376
+ reason
377
+ }));
378
+ const artifactPath = join(input.artifactRoot, input.transactionId);
379
+ yield* makeDirectory(artifactPath, void 0, (reason) => new ArtifactStoreError({
380
+ path: artifactPath,
381
+ reason
382
+ }));
383
+ return artifactPath;
384
+ });
385
+ const writeCanonicalSignatures = (input) => {
386
+ const result = normalizeSignatures(input);
387
+ const path = join(input.artifactPath, "signatures.json");
388
+ return writeJsonFile(path, result.signatureFile, (reason) => new ArtifactStoreError({
389
+ path,
390
+ reason
391
+ })).pipe(Effect.as(path));
392
+ };
393
+ const writeSubmitResult = (input) => {
394
+ const path = join(input.artifactPath, "submitResult.json");
395
+ return writeJsonFile(path, input.submitResult, (reason) => new ArtifactStoreError({
396
+ path,
397
+ reason
398
+ })).pipe(Effect.as(path));
399
+ };
400
+ const readPreparedTransaction = (path) => readJsonFile(path, (reason) => new ArtifactStoreError({
401
+ path,
402
+ reason
403
+ })).pipe(Effect.flatMap((value) => Schema.decodeUnknown(PreparedTransactionSchema)(value).pipe(Effect.mapError((reason) => new ArtifactStoreError({
404
+ path,
405
+ reason
406
+ })))));
407
+ const getArtifactStatus = (artifactPath) => Effect.gen(function* () {
408
+ if (yield* fileExists(join(artifactPath, "submitResult.json"))) return "submitted";
409
+ if (yield* fileExists(join(artifactPath, "notarizedTransaction.hex"))) return "notarized";
410
+ return "prepared";
411
+ });
412
+ const readArtifactSummary = (artifactPath) => Effect.gen(function* () {
413
+ const prepared = yield* readPreparedTransaction(join(artifactPath, "prepared.json"));
414
+ const status = yield* getArtifactStatus(artifactPath);
415
+ return {
416
+ transactionId: prepared.transactionId,
417
+ path: artifactPath,
418
+ network: prepared.network,
419
+ status,
420
+ intentHash: prepared.intentHash.id ?? prepared.intentHash.hex,
421
+ manifestSourceFile: prepared.manifestSourceFile
422
+ };
423
+ });
424
+ const findTransactionArtifact = (input) => Effect.gen(function* () {
425
+ const artifactPath = join(input.artifactRoot, input.transactionId);
426
+ if (!(yield* fileExists(join(artifactPath, "prepared.json")))) return yield* new ArtifactStoreError({
427
+ path: artifactPath,
428
+ reason: "Transaction artifact not found"
429
+ });
430
+ return artifactPath;
431
+ });
432
+ const findTransactionArtifactOption = (input) => Effect.gen(function* () {
433
+ const artifactPath = join(input.artifactRoot, input.transactionId);
434
+ return (yield* fileExists(join(artifactPath, "prepared.json"))) ? artifactPath : void 0;
435
+ });
436
+ const listTransactionArtifacts = (input) => Effect.gen(function* () {
437
+ if (!(yield* fileExists(input.artifactRoot))) return [];
438
+ const entries = yield* readDirectory(input.artifactRoot, (reason) => new ArtifactStoreError({
439
+ path: input.artifactRoot,
440
+ reason
441
+ }));
442
+ const regex = input.regex ? new RegExp(input.regex) : void 0;
443
+ const pattern = input.pattern?.toLowerCase();
444
+ const summaries = [];
445
+ for (const entry of entries) {
446
+ const artifactPath = join(input.artifactRoot, entry);
447
+ if (!(yield* isDirectory(artifactPath, (reason) => new ArtifactStoreError({
448
+ path: artifactPath,
449
+ reason
450
+ })))) continue;
451
+ const summary = yield* readArtifactSummary(artifactPath);
452
+ const searchable = [
453
+ summary.transactionId,
454
+ summary.intentHash,
455
+ summary.manifestSourceFile
456
+ ];
457
+ if (input.network && summary.network !== input.network) continue;
458
+ if (input.status && summary.status !== input.status) continue;
459
+ if (pattern && !searchable.some((value) => value.toLowerCase().includes(pattern))) continue;
460
+ if (regex && !searchable.some((value) => regex.test(value))) continue;
461
+ summaries.push(summary);
462
+ }
463
+ return summaries.sort((left, right) => left.transactionId.localeCompare(right.transactionId));
464
+ });
465
+ var ArtifactStore = class extends Effect.Service()("ArtifactStore", { sync: () => ({
466
+ createTransactionArtifactDirectory,
467
+ findTransactionArtifactOption,
468
+ findTransactionArtifact,
469
+ listTransactionArtifacts,
470
+ writeSubmitResult,
471
+ writeCanonicalSignatures
472
+ }) }) {};
473
+
474
+ //#endregion
475
+ //#region src/signatureImport.ts
476
+ var SignatureImportError = class extends Data.TaggedError("SignatureImportError") {};
477
+ const scopeKey = (scope) => scope.kind === "subintent" ? `subintent:${scope.subintentId}` : scope.kind;
478
+ const requestIdentity = (input) => [
479
+ input.transactionId,
480
+ scopeKey(input.scope),
481
+ input.account ?? "",
482
+ input.hash.id ?? "",
483
+ input.hash.hex
484
+ ].join("|");
485
+ const templateToSignatureEntry = (template) => ({
486
+ scope: template.scope,
487
+ account: template.account,
488
+ hash: template.hash,
489
+ signingRequestPath: template.signingRequestPath,
490
+ publicKey: template.publicKey,
491
+ signature: template.signature
492
+ });
493
+ const decodeImportableFile = (file) => Effect.gen(function* () {
494
+ if (typeof file !== "object" || file === null || !("type" in file)) return yield* new SignatureImportError({
495
+ code: "INVALID_SIGNATURE_FILE",
496
+ reason: "Workflow file type is missing"
497
+ });
498
+ if (file.type === "signatureTemplate") {
499
+ const template = yield* Schema.decodeUnknown(SignatureTemplateSchema)(file).pipe(Effect.mapError((reason) => new SignatureImportError({
500
+ code: "INVALID_SIGNATURE_FILE",
501
+ reason
502
+ })));
503
+ return {
504
+ transactionId: template.transactionId,
505
+ signatures: [templateToSignatureEntry(template)]
506
+ };
507
+ }
508
+ if (file.type === "batchSignatureFile") return {
509
+ transactionId: null,
510
+ signatures: (yield* Schema.decodeUnknown(BatchSignatureFileSchema)(file).pipe(Effect.mapError((reason) => new SignatureImportError({
511
+ code: "INVALID_SIGNATURE_FILE",
512
+ reason
513
+ })))).signatures.flatMap((item) => item.signatures)
514
+ };
515
+ return yield* Schema.decodeUnknown(SignatureFileSchema)(file).pipe(Effect.mapError((reason) => new SignatureImportError({
516
+ code: "INVALID_SIGNATURE_FILE",
517
+ reason
518
+ })));
519
+ });
520
+ const rejectPlaceholders = (entry) => {
521
+ if (entry.publicKey.hex === PLACEHOLDER_PUBLIC_KEY_HEX) return new SignatureImportError({
522
+ code: "PLACEHOLDER_VALUE",
523
+ reason: `publicKey.hex is still a placeholder for ${scopeKey(entry.scope)}${entry.signingRequestPath ? ` at ${entry.signingRequestPath}` : ""}`
524
+ });
525
+ if (entry.signature.hex === PLACEHOLDER_SIGNATURE_HEX) return new SignatureImportError({
526
+ code: "PLACEHOLDER_VALUE",
527
+ reason: `signature.hex is still a placeholder for ${scopeKey(entry.scope)}${entry.signingRequestPath ? ` at ${entry.signingRequestPath}` : ""}`
528
+ });
529
+ };
530
+ const verifySignature = (entry) => {
531
+ if (!ed25519.verify(Buffer.from(entry.signature.hex, "hex"), Buffer.from(entry.hash.hex, "hex"), Buffer.from(entry.publicKey.hex, "hex"))) return new SignatureImportError({
532
+ code: "INVALID_SIGNATURE",
533
+ reason: entry
534
+ });
535
+ };
536
+ const importSignatures = (input) => Effect.gen(function* () {
537
+ const knownRequests = new Set(input.generatedRequests.map((request) => requestIdentity({
538
+ transactionId: request.transactionId,
539
+ scope: request.scope,
540
+ account: request.account,
541
+ hash: request.hash
542
+ })));
543
+ const imported = [];
544
+ for (const file of input.files) {
545
+ const decoded = yield* decodeImportableFile(file);
546
+ if (decoded.transactionId && decoded.transactionId !== input.transactionId) return yield* new SignatureImportError({
547
+ code: "UNKNOWN_SIGNING_REQUEST",
548
+ reason: decoded.transactionId
549
+ });
550
+ for (const signature of decoded.signatures) {
551
+ const placeholderError = rejectPlaceholders(signature);
552
+ if (placeholderError) return yield* placeholderError;
553
+ const identity = requestIdentity({
554
+ transactionId: input.transactionId,
555
+ scope: signature.scope,
556
+ account: signature.account,
557
+ hash: signature.hash
558
+ });
559
+ if (!knownRequests.has(identity)) return yield* new SignatureImportError({
560
+ code: "UNKNOWN_SIGNING_REQUEST",
561
+ reason: identity
562
+ });
563
+ const verificationError = verifySignature(signature);
564
+ if (verificationError) return yield* verificationError;
565
+ imported.push(signature);
566
+ }
567
+ }
568
+ return normalizeSignatures({
569
+ transactionId: input.transactionId,
570
+ existing: input.existing,
571
+ imported
572
+ });
573
+ });
574
+ var SignatureImporter = class extends Effect.Service()("SignatureImporter", { sync: () => ({ importSignatures }) }) {};
575
+
576
+ //#endregion
577
+ //#region src/addSignatures.ts
578
+ const readJson$2 = (path) => readJsonFile(path, (reason) => reason);
579
+ const readPrepared = (artifactPath) => readJson$2(join(artifactPath, "prepared.json")).pipe(Effect.flatMap(Schema.decodeUnknown(PreparedTransactionSchema)));
580
+ const readSigningRequest$1 = (artifactPath, requestPath) => readJson$2(join(artifactPath, requestPath)).pipe(Effect.flatMap(Schema.decodeUnknown(SigningRequestSchema)));
581
+ const readExistingSignatures = (artifactPath) => readJson$2(join(artifactPath, "signatures.json")).pipe(Effect.flatMap(Schema.decodeUnknown(SignatureFileSchema)), Effect.map((file) => file.signatures), Effect.catchAll(() => Effect.succeed([])));
582
+ const requestComplete$2 = (request, signatures) => signatures.some((signature) => signature.scope.kind === request.scope.kind && (signature.scope.kind !== "subintent" || request.scope.kind === "subintent" && signature.scope.subintentId === request.scope.subintentId) && signature.account === request.account && signature.hash.hex === request.hash.hex && signature.hash.id === request.hash.id);
583
+ const addSignaturesToArtifact = (input) => Effect.gen(function* () {
584
+ const artifactPath = yield* findTransactionArtifact(input);
585
+ const prepared = yield* readPrepared(artifactPath);
586
+ const generatedRequests = yield* Effect.all(prepared.signingRequests.map((requestPath) => readSigningRequest$1(artifactPath, requestPath)));
587
+ const existing = yield* readExistingSignatures(artifactPath);
588
+ const files = yield* Effect.all(input.signatureFilePaths.map((signatureFilePath) => readJson$2(signatureFilePath)));
589
+ const importResult = yield* importSignatures({
590
+ transactionId: input.transactionId,
591
+ generatedRequests,
592
+ existing,
593
+ files
594
+ });
595
+ const signaturesPath = yield* writeCanonicalSignatures({
596
+ artifactPath,
597
+ transactionId: input.transactionId,
598
+ existing: [],
599
+ imported: importResult.signatureFile.signatures
600
+ });
601
+ const complete = generatedRequests.every((request) => requestComplete$2(request, importResult.signatureFile.signatures));
602
+ return {
603
+ ...importResult,
604
+ signaturesPath,
605
+ complete
606
+ };
607
+ });
608
+ var AddSignaturesWorkflow = class extends Effect.Service()("AddSignaturesWorkflow", { sync: () => ({ addSignaturesToArtifact }) }) {};
609
+
610
+ //#endregion
611
+ //#region src/config.ts
612
+ const RdxConfigNotarySchema = Schema.Struct({
613
+ publicKey: PublicKeySchema,
614
+ notaryIsSignatory: Schema.optional(Schema.Boolean)
615
+ });
616
+ const RdxConfigFileSchema = Schema.Struct({
617
+ network: Schema.optional(NetworkSchema),
618
+ gatewayBaseUrl: Schema.optional(Schema.String),
619
+ artifactScope: Schema.optional(ArtifactScopeSchema),
620
+ artifactDirectory: Schema.optional(Schema.String),
621
+ notary: Schema.optional(RdxConfigNotarySchema)
622
+ });
623
+ const ResolvedRdxConfigSchema = Schema.Struct({
624
+ network: NetworkSchema,
625
+ gatewayBaseUrl: Schema.optional(Schema.String),
626
+ artifactScope: ArtifactScopeSchema,
627
+ artifactDirectory: Schema.optional(Schema.String),
628
+ artifactRoot: Schema.String,
629
+ notary: Schema.optional(RdxConfigNotarySchema),
630
+ projectConfigPath: Schema.optional(Schema.String),
631
+ globalConfigPath: Schema.optional(Schema.String)
632
+ });
633
+ var ConfigResolutionError = class extends Data.TaggedError("ConfigResolutionError") {};
634
+ const defaultConfig = {
635
+ network: NetworkSchema.make("mainnet"),
636
+ artifactScope: ArtifactScopeSchema.make("local")
637
+ };
638
+ const findNearestProjectConfig = (cwd) => Effect.gen(function* () {
639
+ let directory = resolve(cwd);
640
+ const root = parse(directory).root;
641
+ while (true) {
642
+ const candidate = join(directory, ".rdxconfig.json");
643
+ if (yield* fileExists(candidate)) return candidate;
644
+ if (directory === root) return;
645
+ directory = dirname(directory);
646
+ }
647
+ });
648
+ const readConfigFile = (path) => readJsonFile(path, (reason) => new ConfigResolutionError({
649
+ path,
650
+ reason
651
+ })).pipe(Effect.flatMap((value) => Schema.decodeUnknown(RdxConfigFileSchema)(value).pipe(Effect.mapError((reason) => new ConfigResolutionError({
652
+ path,
653
+ reason
654
+ })))));
655
+ const maybeReadConfigFile = (path) => path === void 0 ? Effect.succeed(void 0) : readConfigFile(path).pipe(Effect.map((config) => [path, config]));
656
+ const resolveArtifactRoot = (input) => {
657
+ if (input.config.artifactDirectory) return resolve(input.cwd, input.config.artifactDirectory);
658
+ if (input.config.artifactScope === "global") return join(input.home, ".rdx", "transactions");
659
+ return join(input.cwd, ".rdx", "transactions");
660
+ };
661
+ const resolveRdxConfig = (input) => Effect.gen(function* () {
662
+ const home = input.home ?? homedir();
663
+ const projectConfigPath = yield* findNearestProjectConfig(input.cwd);
664
+ const globalConfigPath = join(home, ".rdx", "config.json");
665
+ const [globalConfig, projectConfig] = yield* Effect.all([fileExists(globalConfigPath).pipe(Effect.flatMap((exists) => exists ? maybeReadConfigFile(globalConfigPath) : Effect.succeed(void 0))), maybeReadConfigFile(projectConfigPath)]);
666
+ const config = {
667
+ ...defaultConfig,
668
+ ...globalConfig?.[1] ?? {},
669
+ ...projectConfig?.[1] ?? {},
670
+ ...input.overrides ?? {}
671
+ };
672
+ return {
673
+ ...config,
674
+ artifactRoot: resolveArtifactRoot({
675
+ cwd: input.cwd,
676
+ home,
677
+ config
678
+ }),
679
+ projectConfigPath: projectConfig?.[0],
680
+ globalConfigPath: globalConfig?.[0]
681
+ };
682
+ });
683
+ var ConfigResolver = class extends Effect.Service()("ConfigResolver", { sync: () => ({ resolve: resolveRdxConfig }) }) {};
684
+
685
+ //#endregion
686
+ //#region src/llm.ts
687
+ const llmGuide = `# rdx Agent Guide
688
+
689
+ Use \`rdx\` to prepare, inspect, sign-orchestrate, notarize, submit, and track Radix Transaction Manifest V2 workflows from files. It is built for agents: workflow commands are non-interactive and print JSON by default.
690
+
691
+ ## Core Rules
692
+
693
+ - Run \`rdx config show\` before \`tx prepare\` to verify the resolved network and artifact root.
694
+ - After \`tx prepare\`, check \`startEpochInclusive\` and \`endEpochExclusive\` in the command JSON before collecting signatures.
695
+ - \`rdx\` defaults to Mainnet. Prepare on the intended network; do not reuse prepared artifacts across networks.
696
+ - A transaction lifecycle is network-bound from \`tx prepare\` through signing, notarization, submission, and status.
697
+ - \`rdx\` never stores, accepts, or derives private keys.
698
+ - Participants sign only the requested \`hash.hex\` outside \`rdx\` and return a filled signature template or signature file.
699
+ - v1 CLI workflow files support Ed25519 only. Secp256k1 and other curves are rejected.
700
+ - Use \`rdx account derive --public-key <hex>\` to derive a virtual account address offline from an Ed25519 public key.
701
+ - Do not edit signing request files. Fill signature templates or create signature files instead.
702
+ - Do not rerun \`tx prepare\` expecting overwrite. Existing transaction artifact directories are protected.
703
+ - Do not submit until intent, subintent, notary-signatory, and notary signatures required by the artifacts are complete.
704
+ - Use \`tx path\` and \`tx list\` before manually scanning artifact directories.
705
+
706
+ ## Discover Live Inputs
707
+
708
+ \`\`\`sh
709
+ rdx config show
710
+ rdx template print subintents
711
+ rdx template print signing-request
712
+ rdx template print signature-template
713
+ rdx template print signature-file
714
+ rdx --help
715
+ rdx tx prepare --help
716
+ \`\`\`
717
+
718
+ Use template output for workflow file shapes. Do not rely on copied config schemas; use \`rdx config show\` for resolved configuration.
719
+
720
+ ## Transaction Lifecycle
721
+
722
+ 1. Prepare: compile the root manifest plus optional direct child subintents, preview, and write immutable transaction artifacts.
723
+ 2. Inspect: read command JSON output, \`prepared.json\`, copied manifests, signing requests, and templates.
724
+ 3. Intent signing: each participant signs the relevant request \`hash.hex\` out of band.
725
+ 4. Import signatures: use \`tx add-signatures\` one or more times. Imports are normalized into \`signatures.json\`.
726
+ 5. Notarize: after intent/subintent signatures are locally complete, \`tx notarize\` previews the signed intent and creates the notary signing request.
727
+ 6. Notary signing: the notary signs the notary request \`hash.hex\` out of band.
728
+ 7. Import notary signature: use \`tx add-signatures\` again.
729
+ 8. Submit: \`tx submit\` compiles from prepared artifacts plus canonical signatures, writes the submitted payload, broadcasts, polls, and records the result.
730
+ 9. Track: use \`tx status\`, \`tx path\`, and \`tx list\` to inspect local and Gateway state.
731
+
732
+ ## Stable Artifact Mental Model
733
+
734
+ Use command JSON outputs for exact paths. Common artifact files include:
735
+
736
+ - \`prepared.json\`: canonical prepared metadata and signing request/template path index.
737
+ - \`transactionIntent.json\`: encoded Transaction Intent V2 used by later commands.
738
+ - \`staticAnalysis.json\`: full static analysis output.
739
+ - \`rootManifest.rtm\`: copied root manifest.
740
+ - \`subintents/<subintentId>.rtm\`: copied direct child subintent manifests.
741
+ - \`signatures.json\`: canonical normalized signature state.
742
+ - \`notarizedTransaction.hex\`: exact submitted payload.
743
+ - \`submitResult.json\`: submit attempts and network status results.
744
+
745
+ ## Single-party Example
746
+
747
+ \`\`\`sh
748
+ rdx config show
749
+ rdx template print signature-file
750
+ rdx tx prepare --manifest ./tx/root.rtm --notary-file ./tx/notary.json
751
+ rdx tx path txid_example
752
+ rdx tx add-signatures txid_example --file ./tx/signatures/intent-signature.json
753
+ rdx tx notarize txid_example
754
+ rdx tx add-signatures txid_example --file ./tx/signatures/notary-signature.json
755
+ rdx tx submit txid_example
756
+ rdx tx status txid_example
757
+ \`\`\`
758
+
759
+ After \`tx prepare\`, inspect the JSON result for \`transactionId\`, \`artifactPath\`, \`preparedPath\`, \`startEpochInclusive\`, \`endEpochExclusive\`, and generated \`signatureTemplatePaths\`. Fill the generated templates by replacing placeholder Ed25519 public key and signature values. Sign only each request's \`hash.hex\`.
760
+
761
+ ## Multi-party And Subintent Example
762
+
763
+ \`\`\`sh
764
+ rdx config show
765
+ rdx template print subintents
766
+ rdx tx prepare --manifest ./tx/root.rtm --subintents ./tx/subintents.json --notary-file ./tx/notary.json
767
+ rdx tx add-signatures txid_example --file ./party-a/root-signature.json
768
+ rdx tx add-signatures txid_example --file ./party-b/child-one-signature.json
769
+ rdx tx add-signatures txid_example --file ./party-c/batch-signatures.json
770
+ rdx tx notarize txid_example
771
+ rdx tx add-signatures txid_example --file ./notary/notary-signature.json
772
+ rdx tx submit txid_example
773
+ \`\`\`
774
+
775
+ Subintent IDs in \`subintents.json\` are also Radix \`NamedIntent\` values referenced by root \`YIELD_TO_CHILD\` instructions. v1 supports root plus direct child subintents only. Multiple parties can return signatures asynchronously; repeat \`tx add-signatures\` until local completeness allows \`tx notarize\` and later \`tx submit\`.
776
+
777
+ ## Command Examples
778
+
779
+ \`\`\`sh
780
+ rdx config show
781
+ rdx account derive --public-key 1111111111111111111111111111111111111111111111111111111111111111
782
+ rdx account show account_rdx1...
783
+ rdx account fungibles account_rdx1...
784
+ rdx account nfts account_rdx1...
785
+ rdx tx history account_rdx1... --limit 10
786
+ rdx tx prepare --manifest ./tx/root.rtm --notary-file ./tx/notary.json
787
+ rdx tx prepare --manifest ./tx/root.rtm --subintents ./tx/subintents.json --notary-file ./tx/notary.json
788
+ rdx tx add-signatures txid_example --file ./signature.json
789
+ rdx tx add-signatures txid_example --file ./signature-a.json --file ./signature-batch.json
790
+ rdx tx notarize txid_example
791
+ rdx tx submit txid_example
792
+ rdx tx status txid_example
793
+ rdx tx status txid_example --read-only
794
+ rdx tx path txid_example
795
+ rdx tx list
796
+ rdx tx list --pattern root.rtm
797
+ rdx tx list --regex '^txid_' --network mainnet --status prepared
798
+ rdx tx list --with-network-status
799
+ rdx tx list --with-network-status --update-network-status
800
+ rdx template print subintents
801
+ rdx template print signing-request
802
+ rdx template print signature-template
803
+ rdx template print signature-file
804
+ \`\`\`
805
+
806
+ \`account derive\` uses the resolved config network and does not query Gateway. It returns the derived virtual account address, not proof that the account exists on-ledger.
807
+
808
+ ## Troubleshooting
809
+
810
+ - Workflow command failures print structured JSON errors with \`type\`, \`code\`, and \`message\`.
811
+ - Gateway failures include response details in \`message\` when the Gateway returns a structured error body.
812
+ - Inspect \`code\` and \`message\` first; avoid parsing human help text.
813
+ - Use \`rdx tx status\`, \`rdx tx list\`, and \`rdx tx path\` before reading files manually.
814
+ - If the network is wrong, prepare a new transaction for the intended network.
815
+ - If a placeholder public key or signature remains in a file, replace it with a real Ed25519 value produced outside \`rdx\`.
816
+ `;
817
+
818
+ //#endregion
819
+ //#region src/gatewayHttp.ts
820
+ const parseResponseBody = (text) => {
821
+ if (!text) return;
822
+ try {
823
+ return JSON.parse(text);
824
+ } catch {
825
+ return text;
826
+ }
827
+ };
828
+ const gatewayErrorMessage = (label, response) => Effect.gen(function* () {
829
+ const body = parseResponseBody(yield* Effect.promise(() => response.text()));
830
+ const detail = body === void 0 ? "" : `: ${renderJson(body)}`;
831
+ return `${label} failed with status ${response.status}${detail}`;
832
+ });
833
+
834
+ //#endregion
835
+ //#region src/notarize.ts
836
+ var NotarizeError = class extends Data.TaggedError("NotarizeError") {};
837
+ const readJson$1 = (path) => readJsonFile(path, (reason) => new NotarizeError({
838
+ code: "READ_FAILED",
839
+ path,
840
+ reason
841
+ }));
842
+ const readSignatureFile = (input) => Effect.gen(function* () {
843
+ const path = join(input.artifactPath, "signatures.json");
844
+ const exists = yield* fileExists(path);
845
+ if (!exists && input.requiredSignatureCount === 0) return SignatureFileSchema.make({
846
+ type: "signatureFile",
847
+ version: 1,
848
+ transactionId: input.transactionId,
849
+ signatures: []
850
+ });
851
+ if (!exists) return yield* new NotarizeError({
852
+ code: "MISSING_SIGNATURE_FILE",
853
+ path,
854
+ reason: "Run `rdx tx add-signatures <transactionId> --file <signature-file>` before `rdx tx notarize`."
855
+ });
856
+ return yield* readJson$1(path).pipe(Effect.flatMap(Schema.decodeUnknown(SignatureFileSchema)));
857
+ });
858
+ const writeJson$1 = (path, value) => Effect.gen(function* () {
859
+ yield* makeDirectory(dirname(path), { recursive: true }, (reason) => new NotarizeError({
860
+ code: "WRITE_FAILED",
861
+ path,
862
+ reason
863
+ }));
864
+ yield* writeJsonFile(path, value, (reason) => new NotarizeError({
865
+ code: "WRITE_FAILED",
866
+ path,
867
+ reason
868
+ }));
869
+ });
870
+ const requestComplete$1 = (request, signatures) => signatures.some((signature) => signature.scope.kind === request.scope.kind && (signature.scope.kind !== "subintent" || request.scope.kind === "subintent" && signature.scope.subintentId === request.scope.subintentId) && signature.account === request.account && signature.hash.hex === request.hash.hex && signature.hash.id === request.hash.id);
871
+ const toTransactionIntent$1 = (stored) => ({
872
+ transactionHeader: {
873
+ notaryPublicKey: new PublicKey.Ed25519(stored.transactionHeader.notaryPublicKey),
874
+ notaryIsSignatory: stored.transactionHeader.notaryIsSignatory,
875
+ tipBasisPoints: stored.transactionHeader.tipBasisPoints
876
+ },
877
+ rootIntentCore: {
878
+ header: stored.rootIntentCore.header,
879
+ instructions: stored.rootIntentCore.instructions,
880
+ blobs: [],
881
+ message: stored.rootIntentCore.message,
882
+ children: stored.rootIntentCore.children.map(Convert.HexString.toUint8Array)
883
+ },
884
+ nonRootSubintents: stored.nonRootSubintents.map((subintent) => ({ intentCore: {
885
+ header: subintent.intentCore.header,
886
+ instructions: subintent.intentCore.instructions,
887
+ blobs: [],
888
+ message: subintent.intentCore.message,
889
+ children: subintent.intentCore.children.map(Convert.HexString.toUint8Array)
890
+ } }))
891
+ });
892
+ const toSignatureWithPublicKey$1 = (signature) => new SignatureWithPublicKey.Ed25519(signature.signature.hex, signature.publicKey.hex);
893
+ const rootIntentSignatures$1 = (signatures) => signatures.filter((signature) => signature.scope.kind === "rootIntent" || signature.scope.kind === "notarySignatory").map(toSignatureWithPublicKey$1);
894
+ const nonRootSubintentSignatures$1 = (signatures, subintentOrder) => subintentOrder.map((subintentId) => signatures.filter((signature) => signature.scope.kind === "subintent" && signature.scope.subintentId === subintentId).map(toSignatureWithPublicKey$1));
895
+ const rootSignerPublicKeys = (signatures) => signatures.filter((signature) => signature.scope.kind === "rootIntent" || signature.scope.kind === "notarySignatory").map((signature) => new PublicKey.Ed25519(signature.publicKey.hex));
896
+ const nonRootSignerPublicKeys = (signatures, subintentOrder) => subintentOrder.map((subintentId) => signatures.filter((signature) => signature.scope.kind === "subintent" && signature.scope.subintentId === subintentId).map((signature) => new PublicKey.Ed25519(signature.publicKey.hex)));
897
+ const buildNotarizePreviewHex = (input) => Effect.gen(function* () {
898
+ let builderStep = (yield* Effect.tryPromise(() => TransactionV2Builder.new())).header(input.transactionIntent.transactionHeader).rootIntentCore(input.transactionIntent.rootIntentCore);
899
+ const subintentSignatures = nonRootSubintentSignatures$1(input.signatures, input.subintentOrder);
900
+ for (let index = 0; index < input.transactionIntent.nonRootSubintents.length; index += 1) builderStep = builderStep.addSignedSubintent(input.transactionIntent.nonRootSubintents[index], subintentSignatures[index] ?? []);
901
+ const previewTransaction = builderStep.buildPreviewTransaction({
902
+ rootSignerPublicKeys: rootSignerPublicKeys(input.signatures),
903
+ nonRootSubintentSignerPublicKeys: nonRootSignerPublicKeys(input.signatures, input.subintentOrder)
904
+ });
905
+ const compiled = yield* Effect.tryPromise(() => RadixEngineToolkit.PreviewTransactionV2.compile(previewTransaction));
906
+ return Convert.Uint8Array.toHexString(compiled);
907
+ });
908
+ const gatewayBaseUrl$3 = (network) => network === "stokenet" ? "https://stokenet.radixdlt.com" : "https://mainnet.radixdlt.com";
909
+ const gatewayNotarizePreview = (input) => Effect.tryPromise({
910
+ try: async () => {
911
+ const response = await fetch(`${input.config.gatewayBaseUrl ?? gatewayBaseUrl$3(input.config.network)}/transaction/preview-v2`, {
912
+ method: "POST",
913
+ headers: { "content-type": "application/json" },
914
+ body: JSON.stringify({
915
+ preview_transaction: {
916
+ type: "Compiled",
917
+ preview_transaction_hex: input.previewTransactionHex
918
+ },
919
+ flags: {
920
+ assume_all_signature_proofs: false,
921
+ skip_epoch_check: true,
922
+ use_free_credit: true
923
+ },
924
+ opt_ins: { core_api_receipt: false }
925
+ })
926
+ });
927
+ if (!response.ok) throw new Error(await Effect.runPromise(gatewayErrorMessage("Gateway preview", response)));
928
+ const body = await response.json();
929
+ if (body.receipt && body.receipt.status !== "Succeeded") throw new Error(body.receipt.error_message ?? "Preview failed");
930
+ },
931
+ catch: (reason) => new NotarizeError({
932
+ code: "PREVIEW_FAILED",
933
+ reason
934
+ })
935
+ });
936
+ const notarizeTransactionArtifact = (input) => Effect.gen(function* () {
937
+ const artifactPath = yield* findTransactionArtifact(input);
938
+ const preparedPath = join(artifactPath, "prepared.json");
939
+ const prepared = yield* readJson$1(preparedPath).pipe(Effect.flatMap(Schema.decodeUnknown(PreparedTransactionSchema)));
940
+ if (!prepared.notaryPublicKey) return yield* new NotarizeError({
941
+ code: "MISSING_NOTARY_PUBLIC_KEY",
942
+ path: preparedPath
943
+ });
944
+ const requestsRequiringSignatures = (yield* Effect.all(prepared.signingRequests.map((requestPath$1) => readJson$1(join(artifactPath, requestPath$1)).pipe(Effect.flatMap(Schema.decodeUnknown(SigningRequestSchema)))))).filter((request$1) => request$1.scope.kind !== "notary");
945
+ const signatureFile = yield* readSignatureFile({
946
+ artifactPath,
947
+ transactionId: prepared.transactionId,
948
+ requiredSignatureCount: requestsRequiringSignatures.length
949
+ });
950
+ const missingRequest = requestsRequiringSignatures.find((request$1) => !requestComplete$1(request$1, signatureFile.signatures));
951
+ if (missingRequest) {
952
+ const nextCommand = `rdx tx add-signatures ${prepared.transactionId} --file <signature-file>`;
953
+ return yield* new NotarizeError({
954
+ code: "INCOMPLETE_SIGNATURES",
955
+ path: missingRequest.signingRequestPath ?? join(artifactPath, "signatures.json"),
956
+ reason: `Missing signature for ${missingRequest.scope.kind}${missingRequest.account ? ` (${missingRequest.account})` : ""}. Next: ${nextCommand}`
957
+ });
958
+ }
959
+ const transactionIntent = toTransactionIntent$1((yield* readJson$1(join(artifactPath, prepared.transactionIntentPath)).pipe(Effect.map((value) => value))).encoded.value);
960
+ const signedIntent = {
961
+ transactionIntent,
962
+ transactionIntentSignatures: rootIntentSignatures$1(signatureFile.signatures),
963
+ nonRootSubintentSignatures: nonRootSubintentSignatures$1(signatureFile.signatures, prepared.subintentOrder)
964
+ };
965
+ const signedIntentHash = yield* Effect.tryPromise({
966
+ try: () => RadixEngineToolkit.SignedTransactionIntentV2.hash(signedIntent),
967
+ catch: (reason) => new NotarizeError({
968
+ code: "READ_FAILED",
969
+ path: prepared.transactionIntentPath,
970
+ reason
971
+ })
972
+ });
973
+ const signedIntentCompiled = yield* Effect.tryPromise({
974
+ try: () => RadixEngineToolkit.SignedTransactionIntentV2.compile(signedIntent),
975
+ catch: (reason) => new NotarizeError({
976
+ code: "READ_FAILED",
977
+ path: prepared.transactionIntentPath,
978
+ reason
979
+ })
980
+ });
981
+ if (input.previewSignedTransactionIntent) {
982
+ const previewTransactionHex = yield* buildNotarizePreviewHex({
983
+ transactionIntent,
984
+ signatures: signatureFile.signatures,
985
+ subintentOrder: prepared.subintentOrder
986
+ });
987
+ yield* input.previewSignedTransactionIntent(previewTransactionHex);
988
+ }
989
+ const hash = {
990
+ id: signedIntentHash.id,
991
+ hex: Convert.Uint8Array.toHexString(signedIntentHash.hash)
992
+ };
993
+ const requestPath = "signing-requests/notary.json";
994
+ const templatePath = "signature-templates/notary.json";
995
+ const request = {
996
+ type: "signingRequest",
997
+ version: 1,
998
+ transactionId: prepared.transactionId,
999
+ scope: { kind: "notary" },
1000
+ account: null,
1001
+ hash,
1002
+ signingRequestPath: requestPath
1003
+ };
1004
+ const template = {
1005
+ type: "signatureTemplate",
1006
+ version: 1,
1007
+ transactionId: prepared.transactionId,
1008
+ scope: { kind: "notary" },
1009
+ account: null,
1010
+ hash,
1011
+ signingRequestPath: requestPath,
1012
+ publicKey: prepared.notaryPublicKey,
1013
+ signature: {
1014
+ curve: "Ed25519",
1015
+ hex: PLACEHOLDER_SIGNATURE_HEX
1016
+ }
1017
+ };
1018
+ const notarySigningRequestPath = join(artifactPath, requestPath);
1019
+ const notarySignatureTemplatePath = join(artifactPath, templatePath);
1020
+ const signedTransactionIntentPath = join(artifactPath, "signedTransactionIntent.json");
1021
+ yield* writeJson$1(signedTransactionIntentPath, {
1022
+ type: "signedTransactionIntent",
1023
+ version: 1,
1024
+ transactionId: prepared.transactionId,
1025
+ encoded: {
1026
+ kind: "signedTransactionIntentV2",
1027
+ compiledHex: Convert.Uint8Array.toHexString(signedIntentCompiled)
1028
+ }
1029
+ });
1030
+ yield* writeJson$1(notarySigningRequestPath, request);
1031
+ yield* writeJson$1(notarySignatureTemplatePath, template);
1032
+ yield* writeJson$1(preparedPath, {
1033
+ ...prepared,
1034
+ signingRequests: [...new Set([...prepared.signingRequests, requestPath])],
1035
+ signatureTemplates: [...new Set([...prepared.signatureTemplates, templatePath])]
1036
+ });
1037
+ return {
1038
+ transactionId: prepared.transactionId,
1039
+ artifactPath,
1040
+ signedTransactionIntentPath,
1041
+ notarySigningRequestPath,
1042
+ notarySignatureTemplatePath
1043
+ };
1044
+ });
1045
+ var NotarizationCoordinator = class extends Effect.Service()("NotarizationCoordinator", { sync: () => ({
1046
+ notarizeTransactionArtifact,
1047
+ gatewayNotarizePreview
1048
+ }) }) {};
1049
+
1050
+ //#endregion
1051
+ //#region src/signingRequests.ts
1052
+ const scopePath = (scope) => {
1053
+ switch (scope.kind) {
1054
+ case "rootIntent": return "root";
1055
+ case "subintent": return `subintents/${scope.subintentId}`;
1056
+ case "notarySignatory": return "notary-signatory";
1057
+ case "notary": return "notary";
1058
+ }
1059
+ };
1060
+ const workflowFilePath = (directory, scope, account) => account ? `${directory}/${scopePath(scope)}/${account}.json` : `${directory}/${scopePath(scope)}.json`;
1061
+ const makeRequestAndTemplate = (input) => {
1062
+ const requestPath = workflowFilePath("signing-requests", input.scope, input.account);
1063
+ const templatePath = workflowFilePath("signature-templates", input.scope, input.account);
1064
+ const request = {
1065
+ type: "signingRequest",
1066
+ version: 1,
1067
+ transactionId: input.transactionId,
1068
+ scope: input.scope,
1069
+ account: input.account,
1070
+ hash: input.hash,
1071
+ signingRequestPath: requestPath
1072
+ };
1073
+ const template = {
1074
+ type: "signatureTemplate",
1075
+ version: 1,
1076
+ transactionId: input.transactionId,
1077
+ scope: input.scope,
1078
+ account: input.account,
1079
+ hash: input.hash,
1080
+ signingRequestPath: requestPath,
1081
+ publicKey: input.publicKey ?? {
1082
+ curve: "Ed25519",
1083
+ hex: PLACEHOLDER_PUBLIC_KEY_HEX
1084
+ },
1085
+ signature: {
1086
+ curve: "Ed25519",
1087
+ hex: PLACEHOLDER_SIGNATURE_HEX
1088
+ }
1089
+ };
1090
+ return {
1091
+ request: {
1092
+ path: requestPath,
1093
+ file: request
1094
+ },
1095
+ template: {
1096
+ path: templatePath,
1097
+ file: template
1098
+ }
1099
+ };
1100
+ };
1101
+ const generateSigningRequests = (input) => Effect.sync(() => {
1102
+ const requests = [];
1103
+ const templates = [];
1104
+ const push = (item) => {
1105
+ requests.push(item.request);
1106
+ templates.push(item.template);
1107
+ };
1108
+ for (const account of input.authorizationAnalysis.rootIntent) push(makeRequestAndTemplate({
1109
+ transactionId: input.transactionId,
1110
+ scope: { kind: "rootIntent" },
1111
+ account,
1112
+ hash: input.rootIntentHash
1113
+ }));
1114
+ for (const [subintentId, accounts] of Object.entries(input.authorizationAnalysis.subintents)) for (const account of accounts) push(makeRequestAndTemplate({
1115
+ transactionId: input.transactionId,
1116
+ scope: {
1117
+ kind: "subintent",
1118
+ subintentId
1119
+ },
1120
+ account,
1121
+ hash: input.subintentHashes[subintentId]
1122
+ }));
1123
+ if (input.notary.notaryIsSignatory) push(makeRequestAndTemplate({
1124
+ transactionId: input.transactionId,
1125
+ scope: { kind: "notarySignatory" },
1126
+ account: null,
1127
+ hash: input.rootIntentHash,
1128
+ publicKey: input.notary.publicKey
1129
+ }));
1130
+ return {
1131
+ requests,
1132
+ templates
1133
+ };
1134
+ });
1135
+ var SigningRequestGenerator = class extends Effect.Service()("SigningRequestGenerator", { sync: () => ({ generateSigningRequests }) }) {};
1136
+
1137
+ //#endregion
1138
+ //#region src/subintentAssembly.ts
1139
+ var SubintentAssemblyError = class extends Data.TaggedError("SubintentAssemblyError") {};
1140
+ const subintentIdPattern = /^[A-Za-z][A-Za-z0-9_-]{0,63}$/;
1141
+ const yieldToChildPattern = /YIELD_TO_CHILD\s+NamedIntent\("([^"]+)"\)/g;
1142
+ const uniqueInOrder = (items) => {
1143
+ const seen = /* @__PURE__ */ new Set();
1144
+ const result = [];
1145
+ for (const item of items) if (!seen.has(item)) {
1146
+ seen.add(item);
1147
+ result.push(item);
1148
+ }
1149
+ return result;
1150
+ };
1151
+ const extractYieldedSubintentIds = (manifest) => uniqueInOrder([...manifest.matchAll(yieldToChildPattern)].map((match) => match[1]));
1152
+ const useChildDeclaration = (subintentId, intentHash) => `USE_CHILD
1153
+ NamedIntent("${subintentId}")
1154
+ Intent("${intentHash}")
1155
+ ;`;
1156
+ const assembleRootManifest = (input) => Effect.gen(function* () {
1157
+ const providedIds = Object.keys(input.childIntentHashes);
1158
+ const yieldedIds = extractYieldedSubintentIds(input.rootManifest);
1159
+ for (const subintentId of [...providedIds, ...yieldedIds]) if (!subintentIdPattern.test(subintentId)) return yield* new SubintentAssemblyError({
1160
+ code: "INVALID_SUBINTENT_ID",
1161
+ subintentId
1162
+ });
1163
+ for (const subintentId of yieldedIds) if (!(subintentId in input.childIntentHashes)) return yield* new SubintentAssemblyError({
1164
+ code: "MISSING_SUBINTENT",
1165
+ subintentId
1166
+ });
1167
+ for (const subintentId of providedIds) if (!yieldedIds.includes(subintentId)) return yield* new SubintentAssemblyError({
1168
+ code: "UNREFERENCED_SUBINTENT",
1169
+ subintentId
1170
+ });
1171
+ if (providedIds.length === 0) return {
1172
+ rootManifest: input.rootManifest,
1173
+ subintentOrder: []
1174
+ };
1175
+ return {
1176
+ rootManifest: `${yieldedIds.map((subintentId) => useChildDeclaration(subintentId, input.childIntentHashes[subintentId])).join("\n\n")}\n\n${input.rootManifest.trimStart()}`,
1177
+ subintentOrder: yieldedIds
1178
+ };
1179
+ });
1180
+ var SubintentAssembly = class extends Effect.Service()("SubintentAssembly", { sync: () => ({ assembleRootManifest }) }) {};
1181
+
1182
+ //#endregion
1183
+ //#region src/prepare.ts
1184
+ var PreparePreviewError = class extends Data.TaggedError("PreparePreviewError") {};
1185
+ const networkId = (network) => network === "mainnet" ? 1 : 2;
1186
+ const gatewayBaseUrl$2 = (network) => network === "stokenet" ? "https://stokenet.radixdlt.com" : "https://mainnet.radixdlt.com";
1187
+ const defaultEpochWindow = () => ({
1188
+ startEpochInclusive: 1,
1189
+ endEpochExclusive: 10
1190
+ });
1191
+ const epochWindowFromCurrentEpoch = (currentEpoch) => currentEpoch === void 0 ? defaultEpochWindow() : {
1192
+ startEpochInclusive: currentEpoch,
1193
+ endEpochExclusive: currentEpoch + 100
1194
+ };
1195
+ const intentDiscriminator = (input) => Number.parseInt(createHash("sha256").update(input.network).update("\n").update(input.notaryPublicKeyHex).update("\n").update(input.manifest).digest("hex").slice(0, 8), 16);
1196
+ const buildTransactionIntent = (input) => {
1197
+ const id = networkId(input.network);
1198
+ const epochWindow = input.epochWindow ?? defaultEpochWindow();
1199
+ return {
1200
+ transactionHeader: {
1201
+ notaryPublicKey: new PublicKey.Ed25519(input.notary.publicKey.hex),
1202
+ notaryIsSignatory: input.notary.notaryIsSignatory ?? true,
1203
+ tipBasisPoints: 0
1204
+ },
1205
+ rootIntentCore: {
1206
+ header: {
1207
+ networkId: id,
1208
+ startEpochInclusive: epochWindow.startEpochInclusive,
1209
+ endEpochExclusive: epochWindow.endEpochExclusive,
1210
+ intentDiscriminator: intentDiscriminator({
1211
+ manifest: input.manifest,
1212
+ network: input.network,
1213
+ notaryPublicKeyHex: input.notary.publicKey.hex
1214
+ })
1215
+ },
1216
+ instructions: input.manifest,
1217
+ blobs: [],
1218
+ message: { kind: "None" },
1219
+ children: input.childHashes ?? []
1220
+ },
1221
+ nonRootSubintents: input.nonRootSubintents ?? []
1222
+ };
1223
+ };
1224
+ const buildSubintent = (input) => ({ intentCore: {
1225
+ header: {
1226
+ networkId: networkId(input.network),
1227
+ startEpochInclusive: input.epochWindow?.startEpochInclusive ?? defaultEpochWindow().startEpochInclusive,
1228
+ endEpochExclusive: input.epochWindow?.endEpochExclusive ?? defaultEpochWindow().endEpochExclusive,
1229
+ intentDiscriminator: intentDiscriminator({
1230
+ manifest: `${input.subintentId}\n${input.manifest}`,
1231
+ network: input.network,
1232
+ notaryPublicKeyHex: input.notaryPublicKeyHex
1233
+ })
1234
+ },
1235
+ instructions: input.manifest,
1236
+ blobs: [],
1237
+ message: { kind: "None" },
1238
+ children: []
1239
+ } });
1240
+ const encodeIntentCore = (core) => ({
1241
+ header: core.header,
1242
+ instructions: core.instructions,
1243
+ blobs: [],
1244
+ message: core.message,
1245
+ children: core.children.map((child) => Convert.Uint8Array.toHexString(child))
1246
+ });
1247
+ const encodeTransactionIntent = (intent, compiledHex) => ({
1248
+ kind: "transactionIntentV2",
1249
+ value: {
1250
+ transactionHeader: {
1251
+ notaryPublicKey: intent.transactionHeader.notaryPublicKey.hex(),
1252
+ notaryIsSignatory: intent.transactionHeader.notaryIsSignatory,
1253
+ tipBasisPoints: intent.transactionHeader.tipBasisPoints
1254
+ },
1255
+ rootIntentCore: encodeIntentCore(intent.rootIntentCore),
1256
+ nonRootSubintents: intent.nonRootSubintents.map((subintent) => ({ intentCore: encodeIntentCore(subintent.intentCore) }))
1257
+ },
1258
+ compiledHex
1259
+ });
1260
+ const fallbackHashManifest = (manifest) => {
1261
+ const hex = createHash("sha256").update(manifest).digest("hex");
1262
+ return {
1263
+ transactionId: `txid_cli_${hex.slice(0, 32)}`,
1264
+ intentHash: {
1265
+ id: `intent_cli_${hex.slice(0, 32)}`,
1266
+ hex
1267
+ }
1268
+ };
1269
+ };
1270
+ const writeJson = (path, value) => writeJsonFile(path, value, (reason) => reason);
1271
+ const writeWorkflowFile = (artifactPath, relativePath, value) => Effect.gen(function* () {
1272
+ const path = join(artifactPath, relativePath);
1273
+ yield* makeDirectory(join(path, ".."), { recursive: true }, (reason) => reason);
1274
+ yield* writeJson(path, value);
1275
+ return path;
1276
+ });
1277
+ const buildPreparePreviewHex = (intent) => Effect.gen(function* () {
1278
+ let builderStep = (yield* Effect.tryPromise(() => TransactionV2Builder.new())).header(intent.transactionHeader).rootIntentCore(intent.rootIntentCore);
1279
+ for (const subintent of intent.nonRootSubintents) builderStep = builderStep.addSignedSubintent(subintent, []);
1280
+ const previewTransaction = builderStep.buildPreviewTransaction({
1281
+ rootSignerPublicKeys: [],
1282
+ nonRootSubintentSignerPublicKeys: intent.nonRootSubintents.map(() => [])
1283
+ });
1284
+ const compiled = yield* Effect.tryPromise(() => RadixEngineToolkit.PreviewTransactionV2.compile(previewTransaction));
1285
+ return Convert.Uint8Array.toHexString(compiled);
1286
+ });
1287
+ const gatewayPreparePreview = (input) => Effect.tryPromise({
1288
+ try: async () => {
1289
+ const response = await fetch(`${input.config.gatewayBaseUrl ?? gatewayBaseUrl$2(input.config.network)}/transaction/preview-v2`, {
1290
+ method: "POST",
1291
+ headers: { "content-type": "application/json" },
1292
+ body: JSON.stringify({
1293
+ preview_transaction: {
1294
+ type: "Compiled",
1295
+ preview_transaction_hex: input.previewTransactionHex
1296
+ },
1297
+ flags: {
1298
+ assume_all_signature_proofs: true,
1299
+ skip_epoch_check: true,
1300
+ use_free_credit: true
1301
+ },
1302
+ opt_ins: { core_api_receipt: false }
1303
+ })
1304
+ });
1305
+ if (!response.ok) throw new Error(await Effect.runPromise(gatewayErrorMessage("Gateway preview", response)));
1306
+ const body = await response.json();
1307
+ if (body.receipt && body.receipt.status !== "Succeeded") throw new Error(body.receipt.error_message ?? "Preview failed");
1308
+ },
1309
+ catch: (reason) => new PreparePreviewError({ reason })
1310
+ });
1311
+ const gatewayCurrentEpoch = (input) => Effect.tryPromise({
1312
+ try: async () => {
1313
+ const response = await fetch(`${input.config.gatewayBaseUrl ?? gatewayBaseUrl$2(input.config.network)}/status/gateway-status`, {
1314
+ method: "POST",
1315
+ headers: { "content-type": "application/json" },
1316
+ body: "{}"
1317
+ });
1318
+ if (!response.ok) throw new Error(await Effect.runPromise(gatewayErrorMessage("Gateway status", response)));
1319
+ const body = await response.json();
1320
+ if (typeof body.ledger_state?.epoch !== "number") throw new Error("Gateway status response did not include an epoch");
1321
+ return body.ledger_state.epoch;
1322
+ },
1323
+ catch: (reason) => new PreparePreviewError({ reason })
1324
+ });
1325
+ const prepareTransactionArtifacts = (input) => Effect.gen(function* () {
1326
+ const manifest = yield* readFileString(input.manifestPath, (reason) => reason);
1327
+ const subintentsFile = input.subintentsPath ? yield* readJsonFile(input.subintentsPath, (reason) => reason).pipe(Effect.flatMap(Schema.decodeUnknown(SubintentsFileSchema))) : void 0;
1328
+ const childSubintents = yield* Effect.all(Object.entries(subintentsFile?.subintents ?? {}).map(([subintentId, subintent]) => Effect.gen(function* () {
1329
+ const transactionSubintent = buildSubintent({
1330
+ subintentId,
1331
+ manifest: subintent.manifest,
1332
+ network: input.network,
1333
+ notaryPublicKeyHex: input.notary.publicKey.hex,
1334
+ epochWindow: epochWindowFromCurrentEpoch(input.currentEpoch)
1335
+ });
1336
+ const hash = yield* Effect.tryPromise(() => RadixEngineToolkit.SubintentV2.hash(transactionSubintent));
1337
+ return {
1338
+ subintentId,
1339
+ manifest: subintent.manifest,
1340
+ subintent: transactionSubintent,
1341
+ hash
1342
+ };
1343
+ })));
1344
+ const assembled = yield* assembleRootManifest({
1345
+ rootManifest: manifest,
1346
+ childIntentHashes: Object.fromEntries(childSubintents.map((subintent) => [subintent.subintentId, subintent.hash.id]))
1347
+ });
1348
+ const orderedChildSubintents = assembled.subintentOrder.map((subintentId) => childSubintents.find((subintent) => subintent.subintentId === subintentId));
1349
+ const epochWindow = epochWindowFromCurrentEpoch(input.currentEpoch);
1350
+ const intent = buildTransactionIntent({
1351
+ manifest: assembled.rootManifest,
1352
+ network: input.network,
1353
+ notary: input.notary,
1354
+ epochWindow,
1355
+ childHashes: orderedChildSubintents.map((subintent) => subintent.hash.hash.slice()),
1356
+ nonRootSubintents: orderedChildSubintents.map((subintent) => subintent.subintent)
1357
+ });
1358
+ const intentHashResult = yield* Effect.tryPromise(() => RadixEngineToolkit.TransactionIntentV2.hash(intent));
1359
+ const compiledIntent = yield* Effect.tryPromise(() => RadixEngineToolkit.TransactionIntentV2.compile(intent));
1360
+ const staticAnalysisResult = yield* Effect.tryPromise(() => RadixEngineToolkit.TransactionIntentV2.staticallyAnalyze(intent));
1361
+ if (input.previewPreparedTransaction) {
1362
+ const previewTransactionHex = yield* buildPreparePreviewHex(intent);
1363
+ yield* input.previewPreparedTransaction(previewTransactionHex);
1364
+ }
1365
+ const fallback = fallbackHashManifest(manifest);
1366
+ const intentHash = {
1367
+ id: intentHashResult.id,
1368
+ hex: Convert.Uint8Array.toHexString(intentHashResult.hash) ?? fallback.intentHash.hex
1369
+ };
1370
+ const transactionId = intentHashResult.id ?? fallback.transactionId;
1371
+ const artifactPath = yield* createTransactionArtifactDirectory({
1372
+ artifactRoot: input.artifactRoot,
1373
+ transactionId
1374
+ });
1375
+ yield* writeFileString(join(artifactPath, "rootManifest.rtm"), assembled.rootManifest, (reason) => reason);
1376
+ yield* Effect.all(orderedChildSubintents.map((subintent) => Effect.gen(function* () {
1377
+ const path = join(artifactPath, "subintents", `${subintent.subintentId}.rtm`);
1378
+ yield* makeDirectory(join(path, ".."), { recursive: true }, (reason) => reason);
1379
+ yield* writeFileString(path, subintent.manifest, (reason) => reason);
1380
+ })));
1381
+ const transactionIntent = {
1382
+ type: "transactionIntent",
1383
+ version: 1,
1384
+ transactionId,
1385
+ encoded: encodeTransactionIntent(intent, Convert.Uint8Array.toHexString(compiledIntent))
1386
+ };
1387
+ const staticAnalysis = {
1388
+ type: "staticAnalysis",
1389
+ version: 1,
1390
+ transactionId,
1391
+ analysis: staticAnalysisResult
1392
+ };
1393
+ const authorizationAnalysis = {
1394
+ rootIntent: staticAnalysisResult.root_intent.accounts_requiring_auth,
1395
+ subintents: Object.fromEntries(staticAnalysisResult.non_root_subintents.map((subintent, index) => [assembled.subintentOrder[index] ?? `subintent-${index}`, subintent.accounts_requiring_auth]))
1396
+ };
1397
+ const generated = yield* generateSigningRequests({
1398
+ transactionId,
1399
+ rootIntentHash: intentHash,
1400
+ subintentHashes: Object.fromEntries(orderedChildSubintents.map((subintent) => [subintent.subintentId, {
1401
+ id: subintent.hash.id,
1402
+ hex: Convert.Uint8Array.toHexString(subintent.hash.hash)
1403
+ }])),
1404
+ authorizationAnalysis,
1405
+ notary: {
1406
+ publicKey: input.notary.publicKey,
1407
+ notaryIsSignatory: input.notary.notaryIsSignatory ?? true
1408
+ }
1409
+ });
1410
+ yield* Effect.all(generated.requests.map((request) => writeWorkflowFile(artifactPath, request.path, request.file)));
1411
+ const signatureTemplatePaths = yield* Effect.all(generated.templates.map((template) => writeWorkflowFile(artifactPath, template.path, template.file)));
1412
+ const prepared = {
1413
+ type: "preparedTransaction",
1414
+ version: 1,
1415
+ transactionId,
1416
+ network: input.network,
1417
+ intentHash,
1418
+ manifestSourceFile: basename(input.manifestPath),
1419
+ transactionIntentPath: "transactionIntent.json",
1420
+ staticAnalysisPath: "staticAnalysis.json",
1421
+ signingRequests: generated.requests.map((request) => request.path),
1422
+ signatureTemplates: generated.templates.map((template) => template.path),
1423
+ subintentOrder: assembled.subintentOrder,
1424
+ authorizationAnalysis,
1425
+ notaryPublicKey: input.notary.publicKey,
1426
+ notaryIsSignatory: input.notary.notaryIsSignatory ?? true
1427
+ };
1428
+ const transactionIntentPath = join(artifactPath, "transactionIntent.json");
1429
+ const staticAnalysisPath = join(artifactPath, "staticAnalysis.json");
1430
+ const preparedPath = join(artifactPath, "prepared.json");
1431
+ yield* writeJson(transactionIntentPath, transactionIntent);
1432
+ yield* writeJson(staticAnalysisPath, staticAnalysis);
1433
+ yield* writeJson(preparedPath, prepared);
1434
+ return {
1435
+ transactionId,
1436
+ artifactPath,
1437
+ preparedPath,
1438
+ transactionIntentPath,
1439
+ staticAnalysisPath,
1440
+ signatureTemplatePaths,
1441
+ startEpochInclusive: epochWindow.startEpochInclusive,
1442
+ endEpochExclusive: epochWindow.endEpochExclusive
1443
+ };
1444
+ });
1445
+ var TransactionPreparer = class extends Effect.Service()("TransactionPreparer", { sync: () => ({
1446
+ prepareTransactionArtifacts,
1447
+ gatewayPreparePreview,
1448
+ gatewayCurrentEpoch
1449
+ }) }) {};
1450
+
1451
+ //#endregion
1452
+ //#region src/status.ts
1453
+ var TransactionStatusError = class extends Data.TaggedError("TransactionStatusError") {};
1454
+ const gatewayBaseUrl$1 = (network) => network === "stokenet" ? "https://stokenet.radixdlt.com" : "https://mainnet.radixdlt.com";
1455
+ const readExistingSubmitResult$1 = (artifactPath) => readJsonFile(join(artifactPath, "submitResult.json"), (reason) => reason).pipe(Effect.flatMap(Schema.decodeUnknown(SubmitResultSchema)), Effect.catchAll(() => Effect.succeed(void 0)));
1456
+ const gatewayTransactionStatus = (input) => Effect.tryPromise({
1457
+ try: async () => {
1458
+ const response = await fetch(`${input.config.gatewayBaseUrl ?? gatewayBaseUrl$1(input.config.network)}/transaction/status`, {
1459
+ method: "POST",
1460
+ headers: { "content-type": "application/json" },
1461
+ body: JSON.stringify({ intent_hash: input.transactionId })
1462
+ });
1463
+ if (!response.ok) throw new Error(await Effect.runPromise(gatewayErrorMessage("Gateway status", response)));
1464
+ const body = await response.json();
1465
+ return {
1466
+ transactionId: input.transactionId,
1467
+ status: body.intent_status ?? "Unknown",
1468
+ statusDescription: body.intent_status_description ?? "",
1469
+ errorMessage: body.error_message ?? null,
1470
+ checkedAt: (/* @__PURE__ */ new Date()).toISOString()
1471
+ };
1472
+ },
1473
+ catch: (reason) => new TransactionStatusError({
1474
+ transactionId: input.transactionId,
1475
+ reason
1476
+ })
1477
+ });
1478
+ const queryTransactionStatus = (input) => Effect.gen(function* () {
1479
+ const artifactPath = yield* findTransactionArtifactOption({
1480
+ artifactRoot: input.artifactRoot,
1481
+ transactionId: input.transactionId
1482
+ });
1483
+ const networkStatus = yield* input.getNetworkStatus(input.transactionId);
1484
+ if (!artifactPath || input.readOnly) return {
1485
+ transactionId: input.transactionId,
1486
+ artifactPath: artifactPath ?? null,
1487
+ networkStatus,
1488
+ updatedSubmitResultPath: null
1489
+ };
1490
+ const existingSubmitResult = yield* readExistingSubmitResult$1(artifactPath);
1491
+ const updatedSubmitResultPath = yield* writeSubmitResult({
1492
+ artifactPath,
1493
+ submitResult: {
1494
+ type: "submitResult",
1495
+ version: 1,
1496
+ transactionId: input.transactionId,
1497
+ networkStatus,
1498
+ attempts: [...existingSubmitResult?.attempts ?? [], {
1499
+ checkedAt: networkStatus.checkedAt,
1500
+ status: networkStatus.status,
1501
+ statusDescription: networkStatus.statusDescription,
1502
+ errorMessage: networkStatus.errorMessage
1503
+ }]
1504
+ }
1505
+ });
1506
+ return {
1507
+ transactionId: input.transactionId,
1508
+ artifactPath,
1509
+ networkStatus,
1510
+ updatedSubmitResultPath
1511
+ };
1512
+ });
1513
+ const listTransactionArtifactsWithNetworkStatus = (input) => Effect.gen(function* () {
1514
+ const artifacts = yield* listTransactionArtifacts({
1515
+ artifactRoot: input.artifactRoot,
1516
+ pattern: input.pattern,
1517
+ regex: input.regex,
1518
+ network: input.network,
1519
+ status: input.status
1520
+ });
1521
+ return yield* Effect.all(artifacts.map((artifact) => queryTransactionStatus({
1522
+ artifactRoot: input.artifactRoot,
1523
+ transactionId: artifact.transactionId,
1524
+ readOnly: !input.update,
1525
+ getNetworkStatus: input.getNetworkStatus
1526
+ }).pipe(Effect.map((statusResult) => ({
1527
+ ...artifact,
1528
+ networkStatus: statusResult.networkStatus,
1529
+ updatedSubmitResultPath: statusResult.updatedSubmitResultPath
1530
+ })))));
1531
+ });
1532
+ var StatusLifecycle = class extends Effect.Service()("StatusLifecycle", { sync: () => ({
1533
+ queryTransactionStatus,
1534
+ listTransactionArtifactsWithNetworkStatus,
1535
+ gatewayTransactionStatus
1536
+ }) }) {};
1537
+
1538
+ //#endregion
1539
+ //#region src/submit.ts
1540
+ var SubmitError = class extends Data.TaggedError("SubmitError") {};
1541
+ const readJson = (path) => readJsonFile(path, (reason) => new SubmitError({
1542
+ code: "READ_FAILED",
1543
+ path,
1544
+ reason
1545
+ }));
1546
+ const toTransactionIntent = (stored) => ({
1547
+ transactionHeader: {
1548
+ notaryPublicKey: new PublicKey.Ed25519(stored.transactionHeader.notaryPublicKey),
1549
+ notaryIsSignatory: stored.transactionHeader.notaryIsSignatory,
1550
+ tipBasisPoints: stored.transactionHeader.tipBasisPoints
1551
+ },
1552
+ rootIntentCore: {
1553
+ header: stored.rootIntentCore.header,
1554
+ instructions: stored.rootIntentCore.instructions,
1555
+ blobs: [],
1556
+ message: stored.rootIntentCore.message,
1557
+ children: stored.rootIntentCore.children.map(Convert.HexString.toUint8Array)
1558
+ },
1559
+ nonRootSubintents: stored.nonRootSubintents.map((subintent) => ({ intentCore: {
1560
+ header: subintent.intentCore.header,
1561
+ instructions: subintent.intentCore.instructions,
1562
+ blobs: [],
1563
+ message: subintent.intentCore.message,
1564
+ children: subintent.intentCore.children.map(Convert.HexString.toUint8Array)
1565
+ } }))
1566
+ });
1567
+ const toSignatureWithPublicKey = (signature) => new SignatureWithPublicKey.Ed25519(signature.signature.hex, signature.publicKey.hex);
1568
+ const rootIntentSignatures = (signatures) => signatures.filter((signature) => signature.scope.kind === "rootIntent" || signature.scope.kind === "notarySignatory").map(toSignatureWithPublicKey);
1569
+ const nonRootSubintentSignatures = (signatures, subintentOrder) => subintentOrder.map((subintentId) => signatures.filter((signature) => signature.scope.kind === "subintent" && signature.scope.subintentId === subintentId).map(toSignatureWithPublicKey));
1570
+ const findNotarySignature = (signatures) => signatures.find((signature) => signature.scope.kind === "notary");
1571
+ const readSigningRequest = (artifactPath, requestPath) => readJson(join(artifactPath, requestPath)).pipe(Effect.flatMap(Schema.decodeUnknown(SigningRequestSchema)));
1572
+ const requestComplete = (request, signatures) => signatures.some((signature) => signature.scope.kind === request.scope.kind && (signature.scope.kind !== "subintent" || request.scope.kind === "subintent" && signature.scope.subintentId === request.scope.subintentId) && signature.account === request.account && signature.hash.hex === request.hash.hex && signature.hash.id === request.hash.id);
1573
+ const readExistingSubmitResult = (artifactPath) => readJson(join(artifactPath, "submitResult.json")).pipe(Effect.flatMap(Schema.decodeUnknown(SubmitResultSchema)), Effect.catchAll(() => Effect.succeed(void 0)));
1574
+ const successfulSubmitStatuses = new Set(["CommittedSuccess"]);
1575
+ const isSuccessfulSubmitResult = (submitResult) => submitResult ? successfulSubmitStatuses.has(submitResult.networkStatus.status) : false;
1576
+ const gatewayBaseUrl = (network) => network === "stokenet" ? "https://stokenet.radixdlt.com" : "https://mainnet.radixdlt.com";
1577
+ const gatewaySubmitNotarizedTransaction = (input) => Effect.tryPromise({
1578
+ try: async () => {
1579
+ const response = await fetch(`${input.config.gatewayBaseUrl ?? gatewayBaseUrl(input.config.network)}/transaction/submit`, {
1580
+ method: "POST",
1581
+ headers: { "content-type": "application/json" },
1582
+ body: JSON.stringify({ notarized_transaction_hex: input.notarizedTransactionHex })
1583
+ });
1584
+ if (!response.ok) throw new Error(await Effect.runPromise(gatewayErrorMessage("Gateway submit", response)));
1585
+ return NetworkTransactionStatusSchema.make({
1586
+ transactionId: input.transactionId,
1587
+ status: "Submitted",
1588
+ statusDescription: "Submitted to Gateway",
1589
+ errorMessage: null,
1590
+ checkedAt: (/* @__PURE__ */ new Date()).toISOString()
1591
+ });
1592
+ },
1593
+ catch: (reason) => new SubmitError({
1594
+ code: "WRITE_FAILED",
1595
+ reason
1596
+ })
1597
+ });
1598
+ const submitTransactionArtifact = (input) => Effect.gen(function* () {
1599
+ const artifactPath = yield* findTransactionArtifact(input);
1600
+ const existingSubmitResult = yield* readExistingSubmitResult(artifactPath);
1601
+ if (isSuccessfulSubmitResult(existingSubmitResult)) return yield* new SubmitError({
1602
+ code: "ALREADY_SUBMITTED",
1603
+ path: join(artifactPath, "submitResult.json")
1604
+ });
1605
+ const prepared = yield* readJson(join(artifactPath, "prepared.json")).pipe(Effect.flatMap(Schema.decodeUnknown(PreparedTransactionSchema)));
1606
+ const storedIntentFile = yield* readJson(join(artifactPath, prepared.transactionIntentPath)).pipe(Effect.map((value) => value));
1607
+ const signatureFile = yield* readJson(join(artifactPath, "signatures.json")).pipe(Effect.flatMap(Schema.decodeUnknown(SignatureFileSchema)));
1608
+ const missingRequest = (yield* Effect.all(prepared.signingRequests.map((requestPath) => readSigningRequest(artifactPath, requestPath)))).find((request) => !requestComplete(request, signatureFile.signatures));
1609
+ if (missingRequest) return yield* new SubmitError({
1610
+ code: "MISSING_SIGNATURE",
1611
+ path: missingRequest.signingRequestPath,
1612
+ reason: missingRequest
1613
+ });
1614
+ const notarySignatureEntry = findNotarySignature(signatureFile.signatures);
1615
+ if (!notarySignatureEntry) return yield* new SubmitError({
1616
+ code: "MISSING_NOTARY_SIGNATURE",
1617
+ path: join(artifactPath, "signatures.json")
1618
+ });
1619
+ const notarizedTransaction = {
1620
+ signedTransactionIntent: {
1621
+ transactionIntent: toTransactionIntent(storedIntentFile.encoded.value),
1622
+ transactionIntentSignatures: rootIntentSignatures(signatureFile.signatures),
1623
+ nonRootSubintentSignatures: nonRootSubintentSignatures(signatureFile.signatures, prepared.subintentOrder)
1624
+ },
1625
+ notarySignature: new Signature.Ed25519(notarySignatureEntry.signature.hex)
1626
+ };
1627
+ const compiled = yield* Effect.tryPromise({
1628
+ try: () => RadixEngineToolkit.NotarizedTransactionV2.compile(notarizedTransaction),
1629
+ catch: (reason) => new SubmitError({
1630
+ code: "WRITE_FAILED",
1631
+ reason
1632
+ })
1633
+ });
1634
+ const notarizedTransactionHex = Convert.Uint8Array.toHexString(compiled);
1635
+ const notarizedTransactionPath = join(artifactPath, "notarizedTransaction.hex");
1636
+ yield* writeFileString(notarizedTransactionPath, `${notarizedTransactionHex}\n`, (reason) => new SubmitError({
1637
+ code: "WRITE_FAILED",
1638
+ path: notarizedTransactionPath,
1639
+ reason
1640
+ }));
1641
+ const submittedStatus = yield* input.submitNotarizedTransaction(notarizedTransactionHex);
1642
+ const networkStatus = input.pollTransactionStatus ? yield* input.pollTransactionStatus(prepared.transactionId) : submittedStatus;
1643
+ const newAttempts = input.pollTransactionStatus ? [{
1644
+ checkedAt: submittedStatus.checkedAt,
1645
+ status: submittedStatus.status,
1646
+ statusDescription: submittedStatus.statusDescription,
1647
+ errorMessage: submittedStatus.errorMessage
1648
+ }, {
1649
+ checkedAt: networkStatus.checkedAt,
1650
+ status: networkStatus.status,
1651
+ statusDescription: networkStatus.statusDescription,
1652
+ errorMessage: networkStatus.errorMessage
1653
+ }] : [{
1654
+ checkedAt: networkStatus.checkedAt,
1655
+ status: networkStatus.status,
1656
+ statusDescription: networkStatus.statusDescription,
1657
+ errorMessage: networkStatus.errorMessage
1658
+ }];
1659
+ const submitResultPath = yield* writeSubmitResult({
1660
+ artifactPath,
1661
+ submitResult: {
1662
+ type: "submitResult",
1663
+ version: 1,
1664
+ transactionId: prepared.transactionId,
1665
+ networkStatus,
1666
+ attempts: [...existingSubmitResult?.attempts ?? [], ...newAttempts]
1667
+ }
1668
+ });
1669
+ return {
1670
+ transactionId: prepared.transactionId,
1671
+ artifactPath,
1672
+ notarizedTransactionPath,
1673
+ submitResultPath,
1674
+ networkStatus
1675
+ };
1676
+ });
1677
+ var SubmitLifecycle = class extends Effect.Service()("SubmitLifecycle", { sync: () => ({
1678
+ submitTransactionArtifact,
1679
+ gatewaySubmitNotarizedTransaction
1680
+ }) }) {};
1681
+
1682
+ //#endregion
1683
+ //#region src/templates.ts
1684
+ const sampleHash = {
1685
+ id: "intent_or_subintent_hash_id",
1686
+ hex: "aa"
1687
+ };
1688
+ const sampleScope = { kind: "rootIntent" };
1689
+ const workflowTemplate = (kind) => {
1690
+ switch (kind) {
1691
+ case "subintents": return {
1692
+ type: "subintents",
1693
+ version: 1,
1694
+ subintents: { child_one: { manifest: "child-one.rtm" } }
1695
+ };
1696
+ case "signing-request": return {
1697
+ type: "signingRequest",
1698
+ version: 1,
1699
+ transactionId: "txid...",
1700
+ scope: sampleScope,
1701
+ account: "account_rdx1...",
1702
+ hash: sampleHash,
1703
+ signingRequestPath: "signing-requests/root/account_rdx1....json"
1704
+ };
1705
+ case "signature-template": return {
1706
+ type: "signatureTemplate",
1707
+ version: 1,
1708
+ transactionId: "txid...",
1709
+ scope: sampleScope,
1710
+ account: "account_rdx1...",
1711
+ hash: sampleHash,
1712
+ signingRequestPath: "signing-requests/root/account_rdx1....json",
1713
+ publicKey: {
1714
+ curve: "Ed25519",
1715
+ hex: PLACEHOLDER_PUBLIC_KEY_HEX
1716
+ },
1717
+ signature: {
1718
+ curve: "Ed25519",
1719
+ hex: PLACEHOLDER_SIGNATURE_HEX
1720
+ }
1721
+ };
1722
+ case "signature-file": return {
1723
+ type: "signatureFile",
1724
+ version: 1,
1725
+ transactionId: "txid...",
1726
+ signatures: []
1727
+ };
1728
+ }
1729
+ };
1730
+
1731
+ //#endregion
1732
+ //#region src/cli.ts
1733
+ const formatOption = Options.choice("format", ["json", "text"]).pipe(Options.withDefault("json"), Options.withDescription("Output format"));
1734
+ const renderConfigShow = (format, config) => {
1735
+ const result = {
1736
+ type: "commandResult",
1737
+ command: "config show",
1738
+ network: config.network,
1739
+ artifactScope: config.artifactScope,
1740
+ artifactRoot: config.artifactRoot
1741
+ };
1742
+ if (format === "text") return `network: ${result.network}\nartifactScope: ${result.artifactScope}`;
1743
+ return renderJson(result);
1744
+ };
1745
+ const renderTxPath = (format, input) => {
1746
+ const result = {
1747
+ type: "commandResult",
1748
+ command: "tx path",
1749
+ transactionId: input.transactionId,
1750
+ artifactPath: input.artifactPath
1751
+ };
1752
+ if (format === "text") return input.artifactPath;
1753
+ return renderJson(result);
1754
+ };
1755
+ const renderTxList = (format, artifacts) => {
1756
+ const result = {
1757
+ type: "commandResult",
1758
+ command: "tx list",
1759
+ artifacts
1760
+ };
1761
+ if (format === "text") return artifacts.map((artifact) => `${artifact.transactionId}\t${artifact.network}\t${artifact.status}\t${artifact.networkStatus?.status ?? "local"}\t${artifact.path}`).join("\n");
1762
+ return renderJson(result);
1763
+ };
1764
+ const renderTemplate = (kind) => renderJson(workflowTemplate(kind));
1765
+ const renderLlmGuide = () => llmGuide;
1766
+ const renderAddSignatures = (format, result) => {
1767
+ const commandResult = {
1768
+ type: "commandResult",
1769
+ command: "tx add-signatures",
1770
+ acceptedCount: result.acceptedCount,
1771
+ warnings: result.warnings,
1772
+ complete: result.complete,
1773
+ signaturesPath: result.signaturesPath
1774
+ };
1775
+ if (format === "text") return `accepted: ${result.acceptedCount}\ncomplete: ${result.complete}\nsignaturesPath: ${result.signaturesPath}`;
1776
+ return renderJson(commandResult);
1777
+ };
1778
+ const renderTxStatus = (format, result) => {
1779
+ const commandResult = {
1780
+ type: "commandResult",
1781
+ command: "tx status",
1782
+ transactionId: result.transactionId,
1783
+ artifactPath: result.artifactPath,
1784
+ networkStatus: result.networkStatus,
1785
+ updatedSubmitResultPath: result.updatedSubmitResultPath
1786
+ };
1787
+ if (format === "text") return `${result.transactionId}\t${result.networkStatus.status}`;
1788
+ return renderJson(commandResult);
1789
+ };
1790
+ const renderPrepare = (format, result) => {
1791
+ const commandResult = {
1792
+ type: "commandResult",
1793
+ command: "tx prepare",
1794
+ transactionId: result.transactionId,
1795
+ artifactPath: result.artifactPath,
1796
+ preparedPath: result.preparedPath,
1797
+ transactionIntentPath: result.transactionIntentPath,
1798
+ staticAnalysisPath: result.staticAnalysisPath,
1799
+ signatureTemplatePaths: result.signatureTemplatePaths,
1800
+ startEpochInclusive: result.startEpochInclusive,
1801
+ endEpochExclusive: result.endEpochExclusive
1802
+ };
1803
+ if (format === "text") return result.preparedPath;
1804
+ return renderJson(commandResult);
1805
+ };
1806
+ const renderNotarize = (format, result) => {
1807
+ const commandResult = {
1808
+ type: "commandResult",
1809
+ command: "tx notarize",
1810
+ transactionId: result.transactionId,
1811
+ artifactPath: result.artifactPath,
1812
+ signedTransactionIntentPath: result.signedTransactionIntentPath,
1813
+ notarySigningRequestPath: result.notarySigningRequestPath,
1814
+ notarySignatureTemplatePath: result.notarySignatureTemplatePath
1815
+ };
1816
+ if (format === "text") return result.notarySignatureTemplatePath;
1817
+ return renderJson(commandResult);
1818
+ };
1819
+ const renderSubmit = (format, result) => {
1820
+ const commandResult = {
1821
+ type: "commandResult",
1822
+ command: "tx submit",
1823
+ transactionId: result.transactionId,
1824
+ artifactPath: result.artifactPath,
1825
+ notarizedTransactionPath: result.notarizedTransactionPath,
1826
+ submitResultPath: result.submitResultPath,
1827
+ networkStatus: result.networkStatus
1828
+ };
1829
+ if (format === "text") return `${result.transactionId}\t${result.networkStatus.status}`;
1830
+ return renderJson(commandResult);
1831
+ };
1832
+ const renderCommandResult = (format, result) => {
1833
+ if (format === "text") return JSON.stringify(result);
1834
+ return renderJson(result);
1835
+ };
1836
+ const renderAccountDerive = (format, result) => {
1837
+ if (format === "text") return result.accountAddress;
1838
+ return renderJson(result);
1839
+ };
1840
+ const rdxCommand = Command.make("rdx", { format: formatOption }).pipe(Command.withDescription("Agent-first Radix transaction workflow CLI"));
1841
+ const configCommand = Command.make("config").pipe(Command.withDescription("Inspect rdx configuration"));
1842
+ const configShowCommand = Command.make("show", {}, () => Effect.gen(function* () {
1843
+ const { format } = yield* rdxCommand;
1844
+ const config = yield* resolveRdxConfig({ cwd: process.cwd() });
1845
+ yield* Console.log(renderConfigShow(format, config));
1846
+ })).pipe(Command.withDescription("Print resolved configuration"));
1847
+ const llmCommand = Command.make("llm", {}, () => Console.log(renderLlmGuide())).pipe(Command.withDescription("Print compact Markdown instructions for agents"));
1848
+ const accountCommand = Command.make("account").pipe(Command.withDescription("Read account state"));
1849
+ const accountAddressArg = Args.text({ name: "accountAddress" }).pipe(Args.withDescription("Radix account address"));
1850
+ const publicKeyOption = Options.text("public-key").pipe(Options.withDescription("Ed25519 public key hex"));
1851
+ const accountDeriveCommand = Command.make("derive", { publicKey: publicKeyOption }, ({ publicKey }) => Effect.gen(function* () {
1852
+ const { format } = yield* rdxCommand;
1853
+ const result = yield* deriveVirtualAccountAddress({
1854
+ network: (yield* resolveRdxConfig({ cwd: process.cwd() })).network,
1855
+ publicKeyHex: publicKey
1856
+ });
1857
+ yield* Console.log(renderAccountDerive(format, result));
1858
+ })).pipe(Command.withDescription("Derive a virtual account address"));
1859
+ const accountFungiblesCommand = Command.make("fungibles", { accountAddress: accountAddressArg }, ({ accountAddress }) => Effect.gen(function* () {
1860
+ const { format } = yield* rdxCommand;
1861
+ const config = yield* resolveRdxConfig({ cwd: process.cwd() });
1862
+ const result = yield* getAccountFungibles({
1863
+ accountAddress,
1864
+ readFungibles: (address) => gatewayAccountFungibles({
1865
+ config,
1866
+ accountAddress: address
1867
+ })
1868
+ });
1869
+ yield* Console.log(renderCommandResult(format, result));
1870
+ })).pipe(Command.withDescription("Read account fungible tokens"));
1871
+ const accountNftsCommand = Command.make("nfts", { accountAddress: accountAddressArg }, ({ accountAddress }) => Effect.gen(function* () {
1872
+ const { format } = yield* rdxCommand;
1873
+ const config = yield* resolveRdxConfig({ cwd: process.cwd() });
1874
+ const result = yield* getAccountNfts({
1875
+ accountAddress,
1876
+ readNfts: (address) => gatewayAccountNfts({
1877
+ config,
1878
+ accountAddress: address
1879
+ })
1880
+ });
1881
+ yield* Console.log(renderCommandResult(format, result));
1882
+ })).pipe(Command.withDescription("Read account NFTs"));
1883
+ const accountShowCommand = Command.make("show", { accountAddress: accountAddressArg }, ({ accountAddress }) => Effect.gen(function* () {
1884
+ const { format } = yield* rdxCommand;
1885
+ const config = yield* resolveRdxConfig({ cwd: process.cwd() });
1886
+ const result = yield* getAccountDetails({
1887
+ accountAddress,
1888
+ readDetails: (address) => gatewayAccountDetails({
1889
+ config,
1890
+ accountAddress: address
1891
+ })
1892
+ });
1893
+ yield* Console.log(renderCommandResult(format, result));
1894
+ })).pipe(Command.withDescription("Read account details"));
1895
+ const txCommand = Command.make("tx").pipe(Command.withDescription("Work with transaction artifacts"));
1896
+ const manifestOption = Options.file("manifest", { exists: "yes" }).pipe(Options.withDescription("Root Transaction Manifest V2 file"));
1897
+ const notaryFileOption = Options.file("notary-file", { exists: "yes" }).pipe(Options.optional, Options.withDescription("Notary public key workflow file"));
1898
+ const subintentsOption = Options.file("subintents", { exists: "yes" }).pipe(Options.optional, Options.withDescription("Direct child subintents workflow file"));
1899
+ const transactionIdArg = Args.text({ name: "transactionId" }).pipe(Args.withDescription("Deterministic Radix transaction ID"));
1900
+ const txPathCommand = Command.make("path", { transactionId: transactionIdArg }, ({ transactionId }) => Effect.gen(function* () {
1901
+ const { format } = yield* rdxCommand;
1902
+ const artifactPath = yield* findTransactionArtifact({
1903
+ artifactRoot: (yield* resolveRdxConfig({ cwd: process.cwd() })).artifactRoot,
1904
+ transactionId
1905
+ });
1906
+ yield* Console.log(renderTxPath(format, {
1907
+ transactionId,
1908
+ artifactPath
1909
+ }));
1910
+ })).pipe(Command.withDescription("Locate a transaction artifact directory"));
1911
+ const txPrepareCommand = Command.make("prepare", {
1912
+ manifest: manifestOption,
1913
+ notaryFile: notaryFileOption,
1914
+ subintents: subintentsOption
1915
+ }, ({ manifest, notaryFile, subintents }) => Effect.gen(function* () {
1916
+ const { format } = yield* rdxCommand;
1917
+ const config = yield* resolveRdxConfig({ cwd: process.cwd() });
1918
+ const notaryFilePath = Option.getOrUndefined(notaryFile);
1919
+ const notary = notaryFilePath ? yield* readJsonFile(notaryFilePath, (reason) => reason).pipe(Effect.flatMap(Schema.decodeUnknown(NotaryFileSchema))) : config.notary;
1920
+ if (!notary) return yield* Effect.fail(/* @__PURE__ */ new Error("tx prepare requires --notary-file or config notary settings"));
1921
+ const currentEpoch = yield* gatewayCurrentEpoch({ config });
1922
+ const result = yield* prepareTransactionArtifacts({
1923
+ artifactRoot: config.artifactRoot,
1924
+ network: config.network,
1925
+ manifestPath: manifest,
1926
+ subintentsPath: Option.getOrUndefined(subintents),
1927
+ notary,
1928
+ currentEpoch,
1929
+ previewPreparedTransaction: (previewTransactionHex) => gatewayPreparePreview({
1930
+ config,
1931
+ previewTransactionHex
1932
+ })
1933
+ });
1934
+ yield* Console.log(renderPrepare(format, result));
1935
+ })).pipe(Command.withDescription("Prepare transaction artifacts"));
1936
+ const patternOption = Options.text("pattern").pipe(Options.optional);
1937
+ const regexOption = Options.text("regex").pipe(Options.optional);
1938
+ const networkOption = Options.choice("network", ["mainnet", "stokenet"]).pipe(Options.optional);
1939
+ const statusOption = Options.choice("status", [
1940
+ "prepared",
1941
+ "notarized",
1942
+ "submitted"
1943
+ ]).pipe(Options.optional);
1944
+ const withNetworkStatusOption = Options.boolean("with-network-status").pipe(Options.withDescription("Query Gateway status for each listed artifact"));
1945
+ const updateNetworkStatusOption = Options.boolean("update-network-status").pipe(Options.withDescription("Persist refreshed Gateway status into artifacts"));
1946
+ const txListCommand = Command.make("list", {
1947
+ pattern: patternOption,
1948
+ regex: regexOption,
1949
+ network: networkOption,
1950
+ status: statusOption,
1951
+ withNetworkStatus: withNetworkStatusOption,
1952
+ updateNetworkStatus: updateNetworkStatusOption
1953
+ }, ({ network, pattern, regex, status, updateNetworkStatus, withNetworkStatus }) => Effect.gen(function* () {
1954
+ const { format } = yield* rdxCommand;
1955
+ const config = yield* resolveRdxConfig({ cwd: process.cwd() });
1956
+ const listInput = {
1957
+ artifactRoot: config.artifactRoot,
1958
+ pattern: Option.getOrUndefined(pattern),
1959
+ regex: Option.getOrUndefined(regex),
1960
+ network: Option.getOrUndefined(network),
1961
+ status: Option.getOrUndefined(status)
1962
+ };
1963
+ const artifacts = withNetworkStatus || updateNetworkStatus ? yield* listTransactionArtifactsWithNetworkStatus({
1964
+ ...listInput,
1965
+ update: updateNetworkStatus,
1966
+ getNetworkStatus: (id) => gatewayTransactionStatus({
1967
+ config,
1968
+ transactionId: id
1969
+ })
1970
+ }) : yield* listTransactionArtifacts(listInput);
1971
+ yield* Console.log(renderTxList(format, artifacts));
1972
+ })).pipe(Command.withDescription("List local transaction artifacts"));
1973
+ const signatureFileOption = Options.file("file", { exists: "yes" }).pipe(Options.atLeast(1), Options.withDescription("Signature file, batch file, or filled template"));
1974
+ const txAddSignaturesCommand = Command.make("add-signatures", {
1975
+ transactionId: transactionIdArg,
1976
+ files: signatureFileOption
1977
+ }, ({ files, transactionId }) => Effect.gen(function* () {
1978
+ const { format } = yield* rdxCommand;
1979
+ const result = yield* addSignaturesToArtifact({
1980
+ artifactRoot: (yield* resolveRdxConfig({ cwd: process.cwd() })).artifactRoot,
1981
+ transactionId,
1982
+ signatureFilePaths: files
1983
+ });
1984
+ yield* Console.log(renderAddSignatures(format, result));
1985
+ })).pipe(Command.withDescription("Import out-of-band signatures"));
1986
+ const txNotarizeCommand = Command.make("notarize", { transactionId: transactionIdArg }, ({ transactionId }) => Effect.gen(function* () {
1987
+ const { format } = yield* rdxCommand;
1988
+ const config = yield* resolveRdxConfig({ cwd: process.cwd() });
1989
+ const result = yield* notarizeTransactionArtifact({
1990
+ artifactRoot: config.artifactRoot,
1991
+ transactionId,
1992
+ previewSignedTransactionIntent: (previewTransactionHex) => gatewayNotarizePreview({
1993
+ config,
1994
+ previewTransactionHex
1995
+ })
1996
+ });
1997
+ yield* Console.log(renderNotarize(format, result));
1998
+ })).pipe(Command.withDescription("Create notary signing artifacts"));
1999
+ const txSubmitCommand = Command.make("submit", { transactionId: transactionIdArg }, ({ transactionId }) => Effect.gen(function* () {
2000
+ const { format } = yield* rdxCommand;
2001
+ const config = yield* resolveRdxConfig({ cwd: process.cwd() });
2002
+ const result = yield* submitTransactionArtifact({
2003
+ artifactRoot: config.artifactRoot,
2004
+ transactionId,
2005
+ submitNotarizedTransaction: (notarizedTransactionHex) => gatewaySubmitNotarizedTransaction({
2006
+ config,
2007
+ transactionId,
2008
+ notarizedTransactionHex
2009
+ }),
2010
+ pollTransactionStatus: (id) => gatewayTransactionStatus({
2011
+ config,
2012
+ transactionId: id
2013
+ })
2014
+ });
2015
+ yield* Console.log(renderSubmit(format, result));
2016
+ })).pipe(Command.withDescription("Compile and submit a notarized transaction"));
2017
+ const readOnlyOption = Options.boolean("read-only").pipe(Options.withDescription("Do not update local transaction artifacts"));
2018
+ const txStatusCommand = Command.make("status", {
2019
+ transactionId: transactionIdArg,
2020
+ readOnly: readOnlyOption
2021
+ }, ({ readOnly, transactionId }) => Effect.gen(function* () {
2022
+ const { format } = yield* rdxCommand;
2023
+ const config = yield* resolveRdxConfig({ cwd: process.cwd() });
2024
+ const result = yield* queryTransactionStatus({
2025
+ artifactRoot: config.artifactRoot,
2026
+ transactionId,
2027
+ readOnly,
2028
+ getNetworkStatus: (id) => gatewayTransactionStatus({
2029
+ config,
2030
+ transactionId: id
2031
+ })
2032
+ });
2033
+ yield* Console.log(renderTxStatus(format, result));
2034
+ })).pipe(Command.withDescription("Query Gateway transaction status"));
2035
+ const historyLimitOption = Options.integer("limit").pipe(Options.withDefault(10), Options.withDescription("Maximum transactions to return"));
2036
+ const txHistoryCommand = Command.make("history", {
2037
+ accountAddress: accountAddressArg,
2038
+ limit: historyLimitOption
2039
+ }, ({ accountAddress, limit }) => Effect.gen(function* () {
2040
+ const { format } = yield* rdxCommand;
2041
+ const config = yield* resolveRdxConfig({ cwd: process.cwd() });
2042
+ const result = yield* getAccountTransactionHistory({
2043
+ accountAddress,
2044
+ limit,
2045
+ readHistory: (address, itemLimit) => gatewayAccountHistory({
2046
+ config,
2047
+ accountAddress: address,
2048
+ limit: itemLimit
2049
+ })
2050
+ });
2051
+ yield* Console.log(renderCommandResult(format, result));
2052
+ })).pipe(Command.withDescription("Read account transaction history"));
2053
+ const templateCommand = Command.make("template").pipe(Command.withDescription("Print workflow file templates"));
2054
+ const templateKindArg = Args.choice([
2055
+ ["subintents", "subintents"],
2056
+ ["signing-request", "signing-request"],
2057
+ ["signature-template", "signature-template"],
2058
+ ["signature-file", "signature-file"]
2059
+ ], { name: "kind" }).pipe(Args.withDescription("Workflow template kind"));
2060
+ const templatePrintCommand = Command.make("print", { kind: templateKindArg }, ({ kind }) => Console.log(renderTemplate(kind))).pipe(Command.withDescription("Print a JSON workflow template"));
2061
+ const command = rdxCommand.pipe(Command.withSubcommands([
2062
+ accountCommand.pipe(Command.withSubcommands([
2063
+ accountDeriveCommand,
2064
+ accountFungiblesCommand,
2065
+ accountNftsCommand,
2066
+ accountShowCommand
2067
+ ])),
2068
+ configCommand.pipe(Command.withSubcommands([configShowCommand])),
2069
+ llmCommand,
2070
+ templateCommand.pipe(Command.withSubcommands([templatePrintCommand])),
2071
+ txCommand.pipe(Command.withSubcommands([
2072
+ txAddSignaturesCommand,
2073
+ txNotarizeCommand,
2074
+ txPrepareCommand,
2075
+ txPathCommand,
2076
+ txListCommand,
2077
+ txSubmitCommand,
2078
+ txStatusCommand,
2079
+ txHistoryCommand
2080
+ ]))
2081
+ ]));
2082
+ const cli = Command.run(command, {
2083
+ name: "rdx",
2084
+ version: "0.1.0"
2085
+ });
2086
+
2087
+ //#endregion
2088
+ export { findTransactionArtifactOption as $, SubintentAssemblyError as A, OutputFormatSchema as At, ConfigResolver as B, SubintentIdSchema as Bt, queryTransactionStatus as C, BatchSignatureFileSchema as Ct, gatewayPreparePreview as D, NetworkSchema as Dt, gatewayCurrentEpoch as E, HexStringSchema as Et, NotarizeError as F, SignatureEntrySchema as Ft, addSignaturesToArtifact as G, JsonValueSchema as Gt, ResolvedRdxConfigSchema as H, SubmitResultSchema as Ht, gatewayNotarizePreview as I, SignatureFileSchema as It, importSignatures as J, SignatureImportError as K, renderJson as Kt, notarizeTransactionArtifact as L, SignatureTemplateSchema as Lt, SigningRequestGenerator as M, PLACEHOLDER_SIGNATURE_HEX as Mt, generateSigningRequests as N, PreparedTransactionSchema as Nt, prepareTransactionArtifacts as O, NetworkTransactionStatusSchema as Ot, NotarizationCoordinator as P, PublicKeySchema as Pt, findTransactionArtifact as Q, llmGuide as R, SigningRequestSchema as Rt, listTransactionArtifactsWithNetworkStatus as S, AuthorizationAnalysisSchema as St, TransactionPreparer as T, Ed25519SignatureHexSchema as Tt, resolveRdxConfig as U, TransactionHistoryResultSchema as Ut, RdxConfigFileSchema as V, SubintentsFileSchema as Vt, AddSignaturesWorkflow as W, VirtualAccountDerivationSchema as Wt, ArtifactStoreError as X, ArtifactStore as Y, createTransactionArtifactDirectory as Z, gatewaySubmitNotarizedTransaction as _, AccountFungiblesResultSchema as _t, renderConfigShow as a, AccountReadError as at, TransactionStatusError as b, ArtifactScopeSchema as bt, renderPrepare as c, deriveVirtualAccountAddress as ct, renderTxList as d, gatewayAccountHistory as dt, listTransactionArtifacts as et, renderTxPath as f, gatewayAccountNfts as ft, SubmitLifecycle as g, getAccountTransactionHistory as gt, SubmitError as h, getAccountNfts as ht, renderCommandResult as i, readJsonFile as it, assembleRootManifest as j, PLACEHOLDER_PUBLIC_KEY_HEX as jt, SubintentAssembly as k, NotaryFileSchema as kt, renderSubmit as l, gatewayAccountDetails as lt, workflowTemplate as m, getAccountFungibles as mt, renderAccountDerive as n, writeCanonicalSignatures as nt, renderLlmGuide as o, AccountReadService as ot, renderTxStatus as p, getAccountDetails as pt, SignatureImporter as q, toJsonValue as qt, renderAddSignatures as r, writeSubmitResult as rt, renderNotarize as s, InvalidPublicKeyError as st, cli as t, normalizeSignatures as tt, renderTemplate as u, gatewayAccountFungibles as ut, submitTransactionArtifact as v, AccountNftsResultSchema as vt, PreparePreviewError as w, Ed25519PublicKeyHexSchema as wt, gatewayTransactionStatus as x, ArtifactStatusSchema as xt, StatusLifecycle as y, AccountShowResultSchema as yt, ConfigResolutionError as z, SigningScopeSchema as zt };
2089
+ //# sourceMappingURL=cli-n0bR-cOj.js.map