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.
- package/README.md +95 -0
- package/dist/bin/rdx.d.ts +1 -0
- package/dist/bin/rdx.js +95 -0
- package/dist/bin/rdx.js.map +1 -0
- package/dist/cli-n0bR-cOj.js +2089 -0
- package/dist/cli-n0bR-cOj.js.map +1 -0
- package/dist/index.d.ts +969 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +355 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
|
@@ -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
|