@miden-sdk/miden-sdk 0.14.4 → 0.15.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +9 -9
- package/dist/{Cargo-Bwjf7IkR.js → Cargo-CVlXCH_2.js} +7105 -6141
- package/dist/Cargo-CVlXCH_2.js.map +1 -0
- package/dist/api-types.d.ts +17 -47
- package/dist/assets/miden_client_web.wasm +0 -0
- package/dist/crates/miden_client_web.d.ts +122 -76
- package/dist/docs-entry.d.ts +5 -2
- package/dist/eager.js +7 -4
- package/dist/eager.js.map +1 -1
- package/dist/index.d.ts +107 -7
- package/dist/index.js +534 -355
- package/dist/index.js.map +1 -1
- package/dist/wasm.js +1 -1
- package/dist/workers/{Cargo-Bwjf7IkR-Cz54YuXA.js → Cargo-CVlXCH_2-CWA-5vlh.js} +7105 -6141
- package/dist/workers/Cargo-CVlXCH_2-CWA-5vlh.js.map +1 -0
- package/dist/workers/assets/miden_client_web.wasm +0 -0
- package/dist/workers/web-client-methods-worker.js +7129 -6159
- package/dist/workers/web-client-methods-worker.js.map +1 -1
- package/dist/workers/web-client-methods-worker.module.js +23 -19
- package/dist/workers/web-client-methods-worker.module.js.map +1 -1
- package/js/client.js +327 -0
- package/js/node/client-factory.js +117 -0
- package/js/node/loader.js +138 -0
- package/js/node/napi-compat.js +238 -0
- package/js/node-index.js +195 -0
- package/js/resources/accounts.js +224 -0
- package/js/resources/compiler.js +74 -0
- package/js/resources/keystore.js +54 -0
- package/js/resources/notes.js +124 -0
- package/js/resources/settings.js +30 -0
- package/js/resources/tags.js +31 -0
- package/js/resources/transactions.js +533 -0
- package/js/standalone.js +109 -0
- package/js/utils.js +232 -0
- package/lazy/package.json +4 -0
- package/package.json +62 -40
- package/dist/Cargo-Bwjf7IkR.js.map +0 -1
- package/dist/workers/Cargo-Bwjf7IkR-Cz54YuXA.js.map +0 -1
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveAccountRef,
|
|
3
|
+
resolveNoteType,
|
|
4
|
+
resolveTransactionIdHex,
|
|
5
|
+
} from "../utils.js";
|
|
6
|
+
|
|
7
|
+
export class TransactionsResource {
|
|
8
|
+
#inner;
|
|
9
|
+
#getWasm;
|
|
10
|
+
#client;
|
|
11
|
+
|
|
12
|
+
constructor(inner, getWasm, client) {
|
|
13
|
+
this.#inner = inner;
|
|
14
|
+
this.#getWasm = getWasm;
|
|
15
|
+
this.#client = client;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async send(opts) {
|
|
19
|
+
this.#client.assertNotTerminated();
|
|
20
|
+
const wasm = await this.#getWasm();
|
|
21
|
+
|
|
22
|
+
if (opts.returnNote === true) {
|
|
23
|
+
// returnNote path — build the P2ID note in JS so we can return the Note
|
|
24
|
+
// object to the caller (e.g. for out-of-band delivery to the recipient).
|
|
25
|
+
if (opts.reclaimAfter != null || opts.timelockUntil != null) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
"reclaimAfter and timelockUntil are not supported when returnNote is true"
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const senderId = resolveAccountRef(opts.account, wasm);
|
|
32
|
+
const receiverId = resolveAccountRef(opts.to, wasm);
|
|
33
|
+
const faucetId = resolveAccountRef(opts.token, wasm);
|
|
34
|
+
const noteType = resolveNoteType(opts.type, wasm);
|
|
35
|
+
|
|
36
|
+
const note = wasm.Note.createP2IDNote(
|
|
37
|
+
senderId,
|
|
38
|
+
receiverId,
|
|
39
|
+
new wasm.NoteAssets([
|
|
40
|
+
new wasm.FungibleAsset(faucetId, BigInt(opts.amount)),
|
|
41
|
+
]),
|
|
42
|
+
noteType,
|
|
43
|
+
new wasm.NoteAttachment()
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
// NoteArray constructor consumes its elements; use push(¬e) to keep
|
|
47
|
+
// `note` valid so we can return it to the caller below.
|
|
48
|
+
const ownOutputs = new wasm.NoteArray();
|
|
49
|
+
ownOutputs.push(note);
|
|
50
|
+
const request = new wasm.TransactionRequestBuilder()
|
|
51
|
+
.withOwnOutputNotes(ownOutputs)
|
|
52
|
+
.build();
|
|
53
|
+
|
|
54
|
+
const { txId, result } = await this.#submitOrSubmitWithProver(
|
|
55
|
+
senderId,
|
|
56
|
+
request,
|
|
57
|
+
opts.prover
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
if (opts.waitForConfirmation) {
|
|
61
|
+
await this.waitFor(txId.toHex(), { timeout: opts.timeout });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return { txId, note, result };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Default path — note built in WASM with optional reclaim/timelock
|
|
68
|
+
const { accountId, request } = await this.#buildSendRequest(opts, wasm);
|
|
69
|
+
const { txId, result } = await this.#submitOrSubmitWithProver(
|
|
70
|
+
accountId,
|
|
71
|
+
request,
|
|
72
|
+
opts.prover
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
if (opts.waitForConfirmation) {
|
|
76
|
+
await this.waitFor(txId.toHex(), { timeout: opts.timeout });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return { txId, note: null, result };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async mint(opts) {
|
|
83
|
+
this.#client.assertNotTerminated();
|
|
84
|
+
const wasm = await this.#getWasm();
|
|
85
|
+
const { accountId, request } = await this.#buildMintRequest(opts, wasm);
|
|
86
|
+
|
|
87
|
+
const { txId, result } = await this.#submitOrSubmitWithProver(
|
|
88
|
+
accountId,
|
|
89
|
+
request,
|
|
90
|
+
opts.prover
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
if (opts.waitForConfirmation) {
|
|
94
|
+
await this.waitFor(txId.toHex(), { timeout: opts.timeout });
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return { txId, result };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async consume(opts) {
|
|
101
|
+
this.#client.assertNotTerminated();
|
|
102
|
+
const wasm = await this.#getWasm();
|
|
103
|
+
const { accountId, request } = await this.#buildConsumeRequest(opts, wasm);
|
|
104
|
+
|
|
105
|
+
const { txId, result } = await this.#submitOrSubmitWithProver(
|
|
106
|
+
accountId,
|
|
107
|
+
request,
|
|
108
|
+
opts.prover
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
if (opts.waitForConfirmation) {
|
|
112
|
+
await this.waitFor(txId.toHex(), { timeout: opts.timeout });
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return { txId, result };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async consumeAll(opts) {
|
|
119
|
+
this.#client.assertNotTerminated();
|
|
120
|
+
const wasm = await this.#getWasm();
|
|
121
|
+
|
|
122
|
+
// getConsumableNotes takes AccountId by value (consumed by WASM).
|
|
123
|
+
// Save hex so we can reconstruct for submitNewTransaction.
|
|
124
|
+
const accountId = resolveAccountRef(opts.account, wasm);
|
|
125
|
+
const accountIdHex = accountId.toString();
|
|
126
|
+
const consumable = await this.#inner.getConsumableNotes(accountId);
|
|
127
|
+
|
|
128
|
+
if (!consumable || consumable.length === 0) {
|
|
129
|
+
return { txId: null, consumed: 0, remaining: 0 };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const total = consumable.length;
|
|
133
|
+
const toConsume =
|
|
134
|
+
opts.maxNotes != null ? consumable.slice(0, opts.maxNotes) : consumable;
|
|
135
|
+
|
|
136
|
+
if (toConsume.length === 0) {
|
|
137
|
+
return { txId: null, consumed: 0, remaining: total };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const notes = toConsume.map((c) => c.inputNoteRecord().toNote());
|
|
141
|
+
|
|
142
|
+
const request = await this.#inner.newConsumeTransactionRequest(notes);
|
|
143
|
+
|
|
144
|
+
const { txId, result } = await this.#submitOrSubmitWithProver(
|
|
145
|
+
wasm.AccountId.fromHex(accountIdHex),
|
|
146
|
+
request,
|
|
147
|
+
opts.prover
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
if (opts.waitForConfirmation) {
|
|
151
|
+
await this.waitFor(txId.toHex(), { timeout: opts.timeout });
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
txId,
|
|
156
|
+
consumed: toConsume.length,
|
|
157
|
+
remaining: total - toConsume.length,
|
|
158
|
+
result,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async swap(opts) {
|
|
163
|
+
this.#client.assertNotTerminated();
|
|
164
|
+
const wasm = await this.#getWasm();
|
|
165
|
+
const { accountId, request } = await this.#buildSwapRequest(opts, wasm);
|
|
166
|
+
|
|
167
|
+
const { txId, result } = await this.#submitOrSubmitWithProver(
|
|
168
|
+
accountId,
|
|
169
|
+
request,
|
|
170
|
+
opts.prover
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
if (opts.waitForConfirmation) {
|
|
174
|
+
await this.waitFor(txId.toHex(), { timeout: opts.timeout });
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return { txId, result };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async preview(opts) {
|
|
181
|
+
this.#client.assertNotTerminated();
|
|
182
|
+
const wasm = await this.#getWasm();
|
|
183
|
+
|
|
184
|
+
let accountId;
|
|
185
|
+
let request;
|
|
186
|
+
|
|
187
|
+
switch (opts.operation) {
|
|
188
|
+
case "send": {
|
|
189
|
+
({ accountId, request } = await this.#buildSendRequest(opts, wasm));
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
case "mint": {
|
|
193
|
+
({ accountId, request } = await this.#buildMintRequest(opts, wasm));
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
case "consume": {
|
|
197
|
+
({ accountId, request } = await this.#buildConsumeRequest(opts, wasm));
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
case "swap": {
|
|
201
|
+
({ accountId, request } = await this.#buildSwapRequest(opts, wasm));
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
case "custom": {
|
|
205
|
+
accountId = resolveAccountRef(opts.account, wasm);
|
|
206
|
+
request = opts.request;
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
default:
|
|
210
|
+
throw new Error(`Unknown preview operation: ${opts.operation}`);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return await this.#inner.executeForSummary(accountId, request);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
async execute(opts) {
|
|
217
|
+
this.#client.assertNotTerminated();
|
|
218
|
+
const wasm = await this.#getWasm();
|
|
219
|
+
const accountId = resolveAccountRef(opts.account, wasm);
|
|
220
|
+
|
|
221
|
+
let builder = new wasm.TransactionRequestBuilder().withCustomScript(
|
|
222
|
+
opts.script
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
if (opts.foreignAccounts?.length) {
|
|
226
|
+
const accounts = opts.foreignAccounts.map((fa) => {
|
|
227
|
+
// Distinguish { id: AccountRef, storage? } wrapper objects from WASM types
|
|
228
|
+
// (Account/AccountHeader expose .id() as a method, wrappers have .id as a property)
|
|
229
|
+
const isWrapper =
|
|
230
|
+
fa !== null &&
|
|
231
|
+
typeof fa === "object" &&
|
|
232
|
+
"id" in fa &&
|
|
233
|
+
typeof fa.id !== "function";
|
|
234
|
+
const id = resolveAccountRef(isWrapper ? fa.id : fa, wasm);
|
|
235
|
+
const storage =
|
|
236
|
+
isWrapper && fa.storage
|
|
237
|
+
? fa.storage
|
|
238
|
+
: new wasm.AccountStorageRequirements();
|
|
239
|
+
return wasm.ForeignAccount.public(id, storage);
|
|
240
|
+
});
|
|
241
|
+
builder = builder.withForeignAccounts(
|
|
242
|
+
new wasm.ForeignAccountArray(accounts)
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const request = builder.build();
|
|
247
|
+
const { txId, result } = await this.#submitOrSubmitWithProver(
|
|
248
|
+
accountId,
|
|
249
|
+
request,
|
|
250
|
+
opts.prover
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
if (opts.waitForConfirmation) {
|
|
254
|
+
await this.waitFor(txId.toHex(), { timeout: opts.timeout });
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return { txId, result };
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
async executeProgram(opts) {
|
|
261
|
+
this.#client.assertNotTerminated();
|
|
262
|
+
const wasm = await this.#getWasm();
|
|
263
|
+
const accountId = resolveAccountRef(opts.account, wasm);
|
|
264
|
+
|
|
265
|
+
let foreignAccountsArray = new wasm.ForeignAccountArray();
|
|
266
|
+
if (opts.foreignAccounts?.length) {
|
|
267
|
+
const accounts = opts.foreignAccounts.map((fa) => {
|
|
268
|
+
const isWrapper =
|
|
269
|
+
fa !== null &&
|
|
270
|
+
typeof fa === "object" &&
|
|
271
|
+
"id" in fa &&
|
|
272
|
+
typeof fa.id !== "function";
|
|
273
|
+
const id = resolveAccountRef(isWrapper ? fa.id : fa, wasm);
|
|
274
|
+
const storage =
|
|
275
|
+
isWrapper && fa.storage
|
|
276
|
+
? fa.storage
|
|
277
|
+
: new wasm.AccountStorageRequirements();
|
|
278
|
+
return wasm.ForeignAccount.public(id, storage);
|
|
279
|
+
});
|
|
280
|
+
foreignAccountsArray = new wasm.ForeignAccountArray(accounts);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return await this.#inner.executeProgram(
|
|
284
|
+
accountId,
|
|
285
|
+
opts.script,
|
|
286
|
+
opts.adviceInputs ?? new wasm.AdviceInputs(),
|
|
287
|
+
foreignAccountsArray
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
async submit(account, request, opts) {
|
|
292
|
+
this.#client.assertNotTerminated();
|
|
293
|
+
const wasm = await this.#getWasm();
|
|
294
|
+
const accountId = resolveAccountRef(account, wasm);
|
|
295
|
+
return await this.#submitOrSubmitWithProver(
|
|
296
|
+
accountId,
|
|
297
|
+
request,
|
|
298
|
+
opts?.prover
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
async list(query) {
|
|
303
|
+
this.#client.assertNotTerminated();
|
|
304
|
+
const wasm = await this.#getWasm();
|
|
305
|
+
|
|
306
|
+
let filter;
|
|
307
|
+
if (!query) {
|
|
308
|
+
filter = wasm.TransactionFilter.all();
|
|
309
|
+
} else if (query.status === "uncommitted") {
|
|
310
|
+
filter = wasm.TransactionFilter.uncommitted();
|
|
311
|
+
} else if (query.ids) {
|
|
312
|
+
const txIds = query.ids.map((id) =>
|
|
313
|
+
wasm.TransactionId.fromHex(resolveTransactionIdHex(id))
|
|
314
|
+
);
|
|
315
|
+
filter = wasm.TransactionFilter.ids(txIds);
|
|
316
|
+
} else if (query.expiredBefore !== undefined) {
|
|
317
|
+
filter = wasm.TransactionFilter.expiredBefore(query.expiredBefore);
|
|
318
|
+
} else {
|
|
319
|
+
filter = wasm.TransactionFilter.all();
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return await this.#inner.getTransactions(filter);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Polls for transaction confirmation.
|
|
327
|
+
*
|
|
328
|
+
* @param {string | TransactionId} txId - Transaction ID hex string or TransactionId object.
|
|
329
|
+
* @param {WaitOptions} [opts] - Polling options.
|
|
330
|
+
* @param {number} [opts.timeout=60000] - Wall-clock polling timeout in
|
|
331
|
+
* milliseconds. This is NOT a block height — it controls how long the
|
|
332
|
+
* client waits before giving up. Set to 0 to disable the timeout and poll
|
|
333
|
+
* indefinitely until the transaction is committed or discarded.
|
|
334
|
+
* @param {number} [opts.interval=5000] - Polling interval in ms.
|
|
335
|
+
* @param {function} [opts.onProgress] - Called with the current status on
|
|
336
|
+
* each poll iteration ("pending", "submitted", or "committed").
|
|
337
|
+
*/
|
|
338
|
+
async waitFor(txId, opts) {
|
|
339
|
+
this.#client.assertNotTerminated();
|
|
340
|
+
const hex = resolveTransactionIdHex(txId);
|
|
341
|
+
const timeout = opts?.timeout ?? 60_000;
|
|
342
|
+
const interval = opts?.interval ?? 5_000;
|
|
343
|
+
const start = Date.now();
|
|
344
|
+
|
|
345
|
+
const wasm = await this.#getWasm();
|
|
346
|
+
|
|
347
|
+
while (true) {
|
|
348
|
+
const elapsed = Date.now() - start;
|
|
349
|
+
if (timeout > 0 && elapsed >= timeout) {
|
|
350
|
+
throw new Error(
|
|
351
|
+
`Transaction confirmation timed out after ${timeout}ms`
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
try {
|
|
356
|
+
await this.#inner.syncStateWithTimeout(0);
|
|
357
|
+
} catch {
|
|
358
|
+
// Sync may fail transiently; continue polling
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Recreate filter each iteration — WASM consumes it by value
|
|
362
|
+
const filter = wasm.TransactionFilter.ids([
|
|
363
|
+
wasm.TransactionId.fromHex(hex),
|
|
364
|
+
]);
|
|
365
|
+
const txs = await this.#inner.getTransactions(filter);
|
|
366
|
+
|
|
367
|
+
if (txs && txs.length > 0) {
|
|
368
|
+
const tx = txs[0];
|
|
369
|
+
const status = tx.transactionStatus?.();
|
|
370
|
+
|
|
371
|
+
if (status) {
|
|
372
|
+
if (status.isCommitted()) {
|
|
373
|
+
opts?.onProgress?.("committed");
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
if (status.isDiscarded()) {
|
|
377
|
+
throw new Error(`Transaction rejected: ${hex}`);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
opts?.onProgress?.("submitted");
|
|
382
|
+
} else {
|
|
383
|
+
opts?.onProgress?.("pending");
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// ── Shared request builders ──
|
|
391
|
+
|
|
392
|
+
async #buildSendRequest(opts, wasm) {
|
|
393
|
+
const accountId = resolveAccountRef(opts.account, wasm);
|
|
394
|
+
const targetId = resolveAccountRef(opts.to, wasm);
|
|
395
|
+
const faucetId = resolveAccountRef(opts.token, wasm);
|
|
396
|
+
const noteType = resolveNoteType(opts.type, wasm);
|
|
397
|
+
const amount = BigInt(opts.amount);
|
|
398
|
+
|
|
399
|
+
const request = await this.#inner.newSendTransactionRequest(
|
|
400
|
+
accountId,
|
|
401
|
+
targetId,
|
|
402
|
+
faucetId,
|
|
403
|
+
noteType,
|
|
404
|
+
amount,
|
|
405
|
+
opts.reclaimAfter,
|
|
406
|
+
opts.timelockUntil
|
|
407
|
+
);
|
|
408
|
+
return { accountId, request };
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
async #buildMintRequest(opts, wasm) {
|
|
412
|
+
const accountId = resolveAccountRef(opts.account, wasm);
|
|
413
|
+
const targetId = resolveAccountRef(opts.to, wasm);
|
|
414
|
+
const noteType = resolveNoteType(opts.type, wasm);
|
|
415
|
+
const amount = BigInt(opts.amount);
|
|
416
|
+
|
|
417
|
+
// WASM signature: newMintTransactionRequest(target, faucet, noteType, amount)
|
|
418
|
+
const request = await this.#inner.newMintTransactionRequest(
|
|
419
|
+
targetId,
|
|
420
|
+
accountId,
|
|
421
|
+
noteType,
|
|
422
|
+
amount
|
|
423
|
+
);
|
|
424
|
+
return { accountId, request };
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
async #buildConsumeRequest(opts, wasm) {
|
|
428
|
+
const accountId = resolveAccountRef(opts.account, wasm);
|
|
429
|
+
const noteInputs = Array.isArray(opts.notes) ? opts.notes : [opts.notes];
|
|
430
|
+
|
|
431
|
+
const isDirectNote = (input) =>
|
|
432
|
+
input !== null &&
|
|
433
|
+
typeof input === "object" &&
|
|
434
|
+
typeof input.id === "function" &&
|
|
435
|
+
typeof input.toNote !== "function";
|
|
436
|
+
|
|
437
|
+
const hasDirectNotes = noteInputs.some(isDirectNote);
|
|
438
|
+
|
|
439
|
+
if (hasDirectNotes) {
|
|
440
|
+
// At least one raw Note object — use NoteAndArgs builder path
|
|
441
|
+
// (the only WASM path that accepts unauthenticated notes not in the store).
|
|
442
|
+
const resolvedNotes = await Promise.all(
|
|
443
|
+
noteInputs.map(async (input) => {
|
|
444
|
+
if (isDirectNote(input)) return input;
|
|
445
|
+
if (input && typeof input.toNote === "function")
|
|
446
|
+
return input.toNote();
|
|
447
|
+
return await this.#resolveNoteInput(input);
|
|
448
|
+
})
|
|
449
|
+
);
|
|
450
|
+
|
|
451
|
+
const noteAndArgsArr = resolvedNotes.map(
|
|
452
|
+
(note) => new wasm.NoteAndArgs(note, null)
|
|
453
|
+
);
|
|
454
|
+
const request = new wasm.TransactionRequestBuilder()
|
|
455
|
+
.withInputNotes(new wasm.NoteAndArgsArray(noteAndArgsArr))
|
|
456
|
+
.build();
|
|
457
|
+
return { accountId, request };
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// Standard path: all inputs are IDs or records — look up from store.
|
|
461
|
+
const notes = await Promise.all(
|
|
462
|
+
noteInputs.map((input) => this.#resolveNoteInput(input))
|
|
463
|
+
);
|
|
464
|
+
const request = await this.#inner.newConsumeTransactionRequest(notes);
|
|
465
|
+
return { accountId, request };
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
async #buildSwapRequest(opts, wasm) {
|
|
469
|
+
const accountId = resolveAccountRef(opts.account, wasm);
|
|
470
|
+
const offeredFaucetId = resolveAccountRef(opts.offer.token, wasm);
|
|
471
|
+
const requestedFaucetId = resolveAccountRef(opts.request.token, wasm);
|
|
472
|
+
const noteType = resolveNoteType(opts.type, wasm);
|
|
473
|
+
const paybackNoteType = resolveNoteType(
|
|
474
|
+
opts.paybackType ?? opts.type,
|
|
475
|
+
wasm
|
|
476
|
+
);
|
|
477
|
+
|
|
478
|
+
const request = await this.#inner.newSwapTransactionRequest(
|
|
479
|
+
accountId,
|
|
480
|
+
offeredFaucetId,
|
|
481
|
+
BigInt(opts.offer.amount),
|
|
482
|
+
requestedFaucetId,
|
|
483
|
+
BigInt(opts.request.amount),
|
|
484
|
+
noteType,
|
|
485
|
+
paybackNoteType
|
|
486
|
+
);
|
|
487
|
+
return { accountId, request };
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
async #resolveNoteInput(input) {
|
|
491
|
+
if (typeof input === "string") {
|
|
492
|
+
const record = await this.#inner.getInputNote(input);
|
|
493
|
+
if (!record) {
|
|
494
|
+
throw new Error(`Note not found: ${input}`);
|
|
495
|
+
}
|
|
496
|
+
return record.toNote();
|
|
497
|
+
}
|
|
498
|
+
// InputNoteRecord — unwrap to Note
|
|
499
|
+
if (input && typeof input.toNote === "function") {
|
|
500
|
+
return input.toNote();
|
|
501
|
+
}
|
|
502
|
+
// NoteId — has toString() but not toNote() or id() (unlike InputNoteRecord/Note).
|
|
503
|
+
// Check for constructor.fromHex to distinguish from plain objects.
|
|
504
|
+
if (
|
|
505
|
+
input &&
|
|
506
|
+
typeof input.toString === "function" &&
|
|
507
|
+
typeof input.toNote !== "function" &&
|
|
508
|
+
typeof input.id !== "function" &&
|
|
509
|
+
input.constructor?.fromHex !== undefined
|
|
510
|
+
) {
|
|
511
|
+
const hex = input.toString();
|
|
512
|
+
const record = await this.#inner.getInputNote(hex);
|
|
513
|
+
if (!record) {
|
|
514
|
+
throw new Error(`Note not found: ${hex}`);
|
|
515
|
+
}
|
|
516
|
+
return record.toNote();
|
|
517
|
+
}
|
|
518
|
+
// Assume it's already a Note object
|
|
519
|
+
return input;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
async #submitOrSubmitWithProver(accountId, request, perCallProver) {
|
|
523
|
+
const result = await this.#inner.executeTransaction(accountId, request);
|
|
524
|
+
const prover = perCallProver ?? this.#client.defaultProver;
|
|
525
|
+
const proven = prover
|
|
526
|
+
? await this.#inner.proveTransaction(result, prover)
|
|
527
|
+
: await this.#inner.proveTransaction(result);
|
|
528
|
+
const txId = result.id();
|
|
529
|
+
const height = await this.#inner.submitProvenTransaction(proven, result);
|
|
530
|
+
await this.#inner.applyTransaction(result, height);
|
|
531
|
+
return { txId, result };
|
|
532
|
+
}
|
|
533
|
+
}
|
package/js/standalone.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { resolveAccountRef, resolveNoteType } from "./utils.js";
|
|
2
|
+
|
|
3
|
+
// Module-level WASM reference, set by index.js after initialization
|
|
4
|
+
let _wasm = null;
|
|
5
|
+
let _WebClient = null;
|
|
6
|
+
|
|
7
|
+
export function _setWasm(wasm) {
|
|
8
|
+
_wasm = wasm;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function _setWebClient(WebClientClass) {
|
|
12
|
+
_WebClient = WebClientClass;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function getWasm() {
|
|
16
|
+
if (!_wasm) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
"WASM not initialized. Ensure the SDK is loaded before calling standalone utilities."
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
return _wasm;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Creates a P2ID (Pay-to-ID) note.
|
|
26
|
+
*
|
|
27
|
+
* @param {NoteOptions} opts - Note creation options.
|
|
28
|
+
* @returns {Note} The created note.
|
|
29
|
+
*/
|
|
30
|
+
export function createP2IDNote(opts) {
|
|
31
|
+
const wasm = getWasm();
|
|
32
|
+
const sender = resolveAccountRef(opts.from, wasm);
|
|
33
|
+
const target = resolveAccountRef(opts.to, wasm);
|
|
34
|
+
const noteAssets = buildNoteAssets(opts.assets, wasm);
|
|
35
|
+
const noteType = resolveNoteType(opts.type, wasm);
|
|
36
|
+
const attachment = opts.attachment
|
|
37
|
+
? new wasm.NoteAttachment(opts.attachment)
|
|
38
|
+
: new wasm.NoteAttachment([]);
|
|
39
|
+
|
|
40
|
+
return wasm.Note.createP2IDNote(
|
|
41
|
+
sender,
|
|
42
|
+
target,
|
|
43
|
+
noteAssets,
|
|
44
|
+
noteType,
|
|
45
|
+
attachment
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Creates a P2IDE (Pay-to-ID with Expiration) note.
|
|
51
|
+
*
|
|
52
|
+
* @param {P2IDEOptions} opts - Note creation options with timelock/reclaim.
|
|
53
|
+
* @returns {Note} The created note.
|
|
54
|
+
*/
|
|
55
|
+
export function createP2IDENote(opts) {
|
|
56
|
+
const wasm = getWasm();
|
|
57
|
+
const sender = resolveAccountRef(opts.from, wasm);
|
|
58
|
+
const target = resolveAccountRef(opts.to, wasm);
|
|
59
|
+
const noteAssets = buildNoteAssets(opts.assets, wasm);
|
|
60
|
+
const noteType = resolveNoteType(opts.type, wasm);
|
|
61
|
+
const attachment = opts.attachment
|
|
62
|
+
? new wasm.NoteAttachment(opts.attachment)
|
|
63
|
+
: new wasm.NoteAttachment([]);
|
|
64
|
+
|
|
65
|
+
return wasm.Note.createP2IDENote(
|
|
66
|
+
sender,
|
|
67
|
+
target,
|
|
68
|
+
noteAssets,
|
|
69
|
+
opts.reclaimAfter,
|
|
70
|
+
opts.timelockUntil,
|
|
71
|
+
noteType,
|
|
72
|
+
attachment
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Builds a swap tag for note matching.
|
|
78
|
+
*
|
|
79
|
+
* @param {BuildSwapTagOptions} opts - Swap tag options.
|
|
80
|
+
* @returns {NoteTag} The computed swap tag.
|
|
81
|
+
*/
|
|
82
|
+
export function buildSwapTag(opts) {
|
|
83
|
+
const wasm = getWasm();
|
|
84
|
+
if (!_WebClient || typeof _WebClient.buildSwapTag !== "function") {
|
|
85
|
+
throw new Error(
|
|
86
|
+
"WebClient.buildSwapTag is not available. Ensure the SDK is fully loaded."
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
const noteType = resolveNoteType(opts.type, wasm);
|
|
90
|
+
const offeredFaucetId = resolveAccountRef(opts.offer.token, wasm);
|
|
91
|
+
const requestedFaucetId = resolveAccountRef(opts.request.token, wasm);
|
|
92
|
+
|
|
93
|
+
return _WebClient.buildSwapTag(
|
|
94
|
+
noteType,
|
|
95
|
+
offeredFaucetId,
|
|
96
|
+
BigInt(opts.offer.amount),
|
|
97
|
+
requestedFaucetId,
|
|
98
|
+
BigInt(opts.request.amount)
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function buildNoteAssets(assets, wasm) {
|
|
103
|
+
const assetArray = Array.isArray(assets) ? assets : [assets];
|
|
104
|
+
const fungibleAssets = assetArray.map((asset) => {
|
|
105
|
+
const faucetId = resolveAccountRef(asset.token, wasm);
|
|
106
|
+
return new wasm.FungibleAsset(faucetId, BigInt(asset.amount));
|
|
107
|
+
});
|
|
108
|
+
return new wasm.NoteAssets(fungibleAssets);
|
|
109
|
+
}
|