@bananapus/nana-sdk-core 4.0.0 → 5.0.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/bin/wallet-check.mjs +7 -1
- package/dist/cjs/review/confirm.d.ts +4 -0
- package/dist/cjs/review/confirm.d.ts.map +1 -1
- package/dist/cjs/review/confirm.js +14 -3
- package/dist/cjs/review/confirm.js.map +1 -1
- package/dist/cjs/review/contractWrite.d.ts.map +1 -1
- package/dist/cjs/review/contractWrite.js +2 -1
- package/dist/cjs/review/contractWrite.js.map +1 -1
- package/dist/cjs/review/heldWrite.d.ts +4 -0
- package/dist/cjs/review/heldWrite.d.ts.map +1 -1
- package/dist/cjs/review/heldWrite.js +31 -28
- package/dist/cjs/review/heldWrite.js.map +1 -1
- package/dist/cjs/review/index.d.ts +1 -1
- package/dist/cjs/review/index.d.ts.map +1 -1
- package/dist/cjs/review/index.js +6 -2
- package/dist/cjs/review/index.js.map +1 -1
- package/dist/cjs/review/lineError.d.ts +38 -0
- package/dist/cjs/review/lineError.d.ts.map +1 -1
- package/dist/cjs/review/lineError.js +35 -1
- package/dist/cjs/review/lineError.js.map +1 -1
- package/dist/cjs/review/plan.d.ts +0 -2
- package/dist/cjs/review/plan.d.ts.map +1 -1
- package/dist/cjs/review/plan.js +0 -6
- package/dist/cjs/review/plan.js.map +1 -1
- package/dist/cjs/review/react/useHeldSend.js +3 -4
- package/dist/cjs/review/react/useHeldSend.js.map +1 -1
- package/dist/cjs/review/react/useHeldWrite.d.ts.map +1 -1
- package/dist/cjs/review/react/useHeldWrite.js +2 -1
- package/dist/cjs/review/react/useHeldWrite.js.map +1 -1
- package/dist/cjs/review/react/useReviewedRun.d.ts +29 -3
- package/dist/cjs/review/react/useReviewedRun.d.ts.map +1 -1
- package/dist/cjs/review/react/useReviewedRun.js +219 -37
- package/dist/cjs/review/react/useReviewedRun.js.map +1 -1
- package/dist/cjs/review/receipt.d.ts +33 -0
- package/dist/cjs/review/receipt.d.ts.map +1 -1
- package/dist/cjs/review/receipt.js +69 -0
- package/dist/cjs/review/receipt.js.map +1 -1
- package/dist/cjs/review/relayr.d.ts.map +1 -1
- package/dist/cjs/review/relayr.js +1 -0
- package/dist/cjs/review/relayr.js.map +1 -1
- package/dist/cjs/review/relayrSend.d.ts +3 -32
- package/dist/cjs/review/relayrSend.d.ts.map +1 -1
- package/dist/cjs/review/relayrSend.js +78 -226
- package/dist/cjs/review/relayrSend.js.map +1 -1
- package/dist/cjs/review/safeRelayr.d.ts.map +1 -1
- package/dist/cjs/review/safeRelayr.js +4 -8
- package/dist/cjs/review/safeRelayr.js.map +1 -1
- package/dist/cjs/review/safeSend.js +3 -5
- package/dist/cjs/review/safeSend.js.map +1 -1
- package/dist/cjs/review/send.d.ts +38 -7
- package/dist/cjs/review/send.d.ts.map +1 -1
- package/dist/cjs/review/send.js +267 -121
- package/dist/cjs/review/send.js.map +1 -1
- package/dist/cjs/review/sign.d.ts +6 -4
- package/dist/cjs/review/sign.d.ts.map +1 -1
- package/dist/cjs/review/sign.js +22 -18
- package/dist/cjs/review/sign.js.map +1 -1
- package/dist/cjs/review/wallet.d.ts +18 -2
- package/dist/cjs/review/wallet.d.ts.map +1 -1
- package/dist/cjs/review/wallet.js +127 -50
- package/dist/cjs/review/wallet.js.map +1 -1
- package/dist/cjs/review/writeHold.d.ts +38 -1
- package/dist/cjs/review/writeHold.d.ts.map +1 -1
- package/dist/cjs/review/writeHold.js +37 -5
- package/dist/cjs/review/writeHold.js.map +1 -1
- package/dist/cjs/review/writeRecovery.d.ts +11 -0
- package/dist/cjs/review/writeRecovery.d.ts.map +1 -1
- package/dist/cjs/review/writeRecovery.js +38 -5
- package/dist/cjs/review/writeRecovery.js.map +1 -1
- package/dist/esm/review/confirm.d.ts +4 -0
- package/dist/esm/review/confirm.d.ts.map +1 -1
- package/dist/esm/review/confirm.js +13 -3
- package/dist/esm/review/confirm.js.map +1 -1
- package/dist/esm/review/contractWrite.d.ts.map +1 -1
- package/dist/esm/review/contractWrite.js +3 -2
- package/dist/esm/review/contractWrite.js.map +1 -1
- package/dist/esm/review/heldWrite.d.ts +4 -0
- package/dist/esm/review/heldWrite.d.ts.map +1 -1
- package/dist/esm/review/heldWrite.js +30 -27
- package/dist/esm/review/heldWrite.js.map +1 -1
- package/dist/esm/review/index.d.ts +1 -1
- package/dist/esm/review/index.d.ts.map +1 -1
- package/dist/esm/review/index.js +1 -1
- package/dist/esm/review/index.js.map +1 -1
- package/dist/esm/review/lineError.d.ts +38 -0
- package/dist/esm/review/lineError.d.ts.map +1 -1
- package/dist/esm/review/lineError.js +33 -1
- package/dist/esm/review/lineError.js.map +1 -1
- package/dist/esm/review/plan.d.ts +0 -2
- package/dist/esm/review/plan.d.ts.map +1 -1
- package/dist/esm/review/plan.js +0 -5
- package/dist/esm/review/plan.js.map +1 -1
- package/dist/esm/review/react/useHeldSend.js +3 -4
- package/dist/esm/review/react/useHeldSend.js.map +1 -1
- package/dist/esm/review/react/useHeldWrite.d.ts.map +1 -1
- package/dist/esm/review/react/useHeldWrite.js +2 -1
- package/dist/esm/review/react/useHeldWrite.js.map +1 -1
- package/dist/esm/review/react/useReviewedRun.d.ts +29 -3
- package/dist/esm/review/react/useReviewedRun.d.ts.map +1 -1
- package/dist/esm/review/react/useReviewedRun.js +220 -38
- package/dist/esm/review/react/useReviewedRun.js.map +1 -1
- package/dist/esm/review/receipt.d.ts +33 -0
- package/dist/esm/review/receipt.d.ts.map +1 -1
- package/dist/esm/review/receipt.js +66 -0
- package/dist/esm/review/receipt.js.map +1 -1
- package/dist/esm/review/relayr.d.ts.map +1 -1
- package/dist/esm/review/relayr.js +2 -1
- package/dist/esm/review/relayr.js.map +1 -1
- package/dist/esm/review/relayrSend.d.ts +3 -32
- package/dist/esm/review/relayrSend.d.ts.map +1 -1
- package/dist/esm/review/relayrSend.js +85 -232
- package/dist/esm/review/relayrSend.js.map +1 -1
- package/dist/esm/review/safeRelayr.d.ts.map +1 -1
- package/dist/esm/review/safeRelayr.js +4 -8
- package/dist/esm/review/safeRelayr.js.map +1 -1
- package/dist/esm/review/safeSend.js +4 -6
- package/dist/esm/review/safeSend.js.map +1 -1
- package/dist/esm/review/send.d.ts +38 -7
- package/dist/esm/review/send.d.ts.map +1 -1
- package/dist/esm/review/send.js +270 -125
- package/dist/esm/review/send.js.map +1 -1
- package/dist/esm/review/sign.d.ts +6 -4
- package/dist/esm/review/sign.d.ts.map +1 -1
- package/dist/esm/review/sign.js +24 -20
- package/dist/esm/review/sign.js.map +1 -1
- package/dist/esm/review/wallet.d.ts +18 -2
- package/dist/esm/review/wallet.d.ts.map +1 -1
- package/dist/esm/review/wallet.js +128 -51
- package/dist/esm/review/wallet.js.map +1 -1
- package/dist/esm/review/writeHold.d.ts +38 -1
- package/dist/esm/review/writeHold.d.ts.map +1 -1
- package/dist/esm/review/writeHold.js +37 -6
- package/dist/esm/review/writeHold.js.map +1 -1
- package/dist/esm/review/writeRecovery.d.ts +11 -0
- package/dist/esm/review/writeRecovery.d.ts.map +1 -1
- package/dist/esm/review/writeRecovery.js +38 -5
- package/dist/esm/review/writeRecovery.js.map +1 -1
- package/package.json +1 -1
package/dist/cjs/review/send.js
CHANGED
|
@@ -4,12 +4,16 @@ exports.SAFE_BATCH_UNFOLLOWABLE_LINE = exports.SAFE_BATCH_UNSUPPORTED_LINE = voi
|
|
|
4
4
|
exports.reviewPlan = reviewPlan;
|
|
5
5
|
exports.sendReviewed = sendReviewed;
|
|
6
6
|
exports.resumeReviewed = resumeReviewed;
|
|
7
|
+
exports.completeReviewedStep = completeReviewedStep;
|
|
7
8
|
const lineError_js_1 = require("./lineError.js");
|
|
8
9
|
const viem_1 = require("viem");
|
|
9
10
|
const confirm_js_1 = require("./confirm.js");
|
|
10
11
|
const contractWrite_js_1 = require("./contractWrite.js");
|
|
11
12
|
const constants_js_1 = require("../constants.js");
|
|
12
13
|
const gas_js_1 = require("./gas.js");
|
|
14
|
+
const heldWrite_js_1 = require("./heldWrite.js");
|
|
15
|
+
const reviewQueue_js_1 = require("./reviewQueue.js");
|
|
16
|
+
const pause_js_1 = require("../pause.js");
|
|
13
17
|
const safeService_js_1 = require("../safeService.js");
|
|
14
18
|
const messages_js_1 = require("./messages.js");
|
|
15
19
|
const model_js_1 = require("./model.js");
|
|
@@ -194,14 +198,15 @@ funded) {
|
|
|
194
198
|
if (!(0, simulation_js_1.isRevert)(error))
|
|
195
199
|
return { status: "unavailable", message: SIMULATION_UNAVAILABLE };
|
|
196
200
|
const reason = (0, simulation_js_1.revertReason)(error);
|
|
197
|
-
|
|
201
|
+
// A sequence's failure is the SDK's line naming its call.
|
|
202
|
+
const failure = error instanceof lineError_js_1.ReviewLineError
|
|
203
|
+
? error
|
|
204
|
+
: (0, simulation_js_1.simulationFailure)(`${labelOf(calls[steps[0]], steps[0])} cannot run on ${chainName}: ${reason ?? simulation_js_1.REVERT_UNKNOWN_LINE}`, error);
|
|
205
|
+
return (0, confirm_js_1.failedSimulation)({
|
|
198
206
|
status: "failed",
|
|
199
|
-
|
|
200
|
-
message: error instanceof lineError_js_1.ReviewLineError
|
|
201
|
-
? error.message
|
|
202
|
-
: `${labelOf(calls[steps[0]], steps[0])} cannot run on ${chainName}: ${reason ?? simulation_js_1.REVERT_UNKNOWN_LINE}`,
|
|
207
|
+
message: failure.message,
|
|
203
208
|
explained: reason !== null,
|
|
204
|
-
};
|
|
209
|
+
}, failure);
|
|
205
210
|
}
|
|
206
211
|
});
|
|
207
212
|
// A revert on one chain is reported at once, whatever the others still wait on.
|
|
@@ -243,8 +248,8 @@ async function promptSimulated(model, fromOf, calls, run, blocks, clientFor, sig
|
|
|
243
248
|
* One review of calls an app then sends one by one, across chains and
|
|
244
249
|
* paths: core's prompt over exactly `action.calls`, simulated as their
|
|
245
250
|
* senders, and nothing else. The plan it returns lets {@link sendReviewed},
|
|
246
|
-
* `signReviewed`, `proposeReviewedSafeTransaction
|
|
247
|
-
*
|
|
251
|
+
* `signReviewed`, `proposeReviewedSafeTransaction` and `payRelayrReviewed`
|
|
252
|
+
* skip their prompt for a call identical to one of its
|
|
248
253
|
* calls (account, chain, sender, target, data, value and gas: a call's
|
|
249
254
|
* exact gas limit, or a forward request's signed gas, is set before the
|
|
250
255
|
* review), each spent once, for {@link REVIEWED_PLAN_TTL_MS} after confirm.
|
|
@@ -381,38 +386,21 @@ async function resumeReviewed(record, action, deps) {
|
|
|
381
386
|
// wallet") or nothing was sent: then the step is reviewed and sent again.
|
|
382
387
|
if (!state.settled && !handle.released(reservation))
|
|
383
388
|
throw new lineError_js_1.ReviewLineError(sequence_js_1.REVIEWED_SEQUENCE_UNCERTAIN_LINE);
|
|
384
|
-
delete saved.sending;
|
|
385
|
-
delete saved.proposed;
|
|
386
389
|
const { settled } = state;
|
|
387
|
-
|
|
388
|
-
|
|
390
|
+
// Read before anything advances: a failed read leaves the step to resume again.
|
|
391
|
+
const receipt = await confirmedReceipt(settled, deps.clientFor(call.chainId));
|
|
392
|
+
// This sequence's own step: it is recorded, told, and only then
|
|
393
|
+
// acknowledged, so it is never offered again.
|
|
394
|
+
const kept = await recordSending(saved, settled, storage, expected);
|
|
395
|
+
await tellConfirmed(action, handle, call, step, settled, receipt);
|
|
396
|
+
if (settled?.result === "success")
|
|
389
397
|
await handle.acknowledge(settled);
|
|
390
|
-
|
|
391
|
-
}
|
|
392
|
-
/** Tells the site of the step that went through while away, once saved and when its receipt reads. */
|
|
393
|
-
const told = async () => {
|
|
394
|
-
if (settled?.result !== "success" || !action.onConfirmed)
|
|
395
|
-
return;
|
|
396
|
-
try {
|
|
397
|
-
const receipt = await deps
|
|
398
|
-
.clientFor(call.chainId)
|
|
399
|
-
.getTransactionReceipt({ hash: settled.hash });
|
|
400
|
-
if (receipt.status === "success")
|
|
401
|
-
await action.onConfirmed(call, step, receipt);
|
|
402
|
-
}
|
|
403
|
-
catch {
|
|
404
|
-
/* The step went through whatever the read or the site's callback does. */
|
|
405
|
-
}
|
|
406
|
-
};
|
|
407
|
-
if (saved.completed.length === saved.calls.length) {
|
|
408
|
-
await (0, sequence_js_1.removeReviewedSequence)(saved, storage, expected);
|
|
409
|
-
await told();
|
|
398
|
+
if (kept === null) {
|
|
410
399
|
const total = saved.calls.length;
|
|
411
|
-
deps.onProgress
|
|
400
|
+
(0, receipt_js_1.tell)(deps.onProgress, { step: total - 1, total, phase: "done" });
|
|
412
401
|
return { status: "done", hashes: saved.completed, receipts: [] };
|
|
413
402
|
}
|
|
414
|
-
expected =
|
|
415
|
-
await told();
|
|
403
|
+
expected = kept;
|
|
416
404
|
}
|
|
417
405
|
return send({
|
|
418
406
|
...action,
|
|
@@ -421,8 +409,133 @@ async function resumeReviewed(record, action, deps) {
|
|
|
421
409
|
scope: saved.scope,
|
|
422
410
|
}, deps, { record: saved, storage, raw: expected });
|
|
423
411
|
}
|
|
412
|
+
/**
|
|
413
|
+
* Ends `saved`'s step in flight as its hold settled it: a success is
|
|
414
|
+
* recorded as completed. Removes a finished sequence (null) or saves it over
|
|
415
|
+
* `expected`, returning the value written.
|
|
416
|
+
*/
|
|
417
|
+
async function recordSending(saved, settled, storage, expected) {
|
|
418
|
+
delete saved.sending;
|
|
419
|
+
delete saved.proposed;
|
|
420
|
+
if (settled?.result === "success")
|
|
421
|
+
saved.completed.push(settled.hash);
|
|
422
|
+
if (saved.completed.length < saved.calls.length)
|
|
423
|
+
return (0, sequence_js_1.saveReviewedSequence)(saved, storage, expected);
|
|
424
|
+
await (0, sequence_js_1.removeReviewedSequence)(saved, storage, expected);
|
|
425
|
+
return null;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* The receipt of a step its hold settled ({@link heldReceipt}), checked
|
|
429
|
+
* before anything advances: a read that fails or disagrees with the hold
|
|
430
|
+
* throws. Null when the settlement has no transaction (an expiry).
|
|
431
|
+
*/
|
|
432
|
+
async function confirmedReceipt(settled, client, given) {
|
|
433
|
+
return settled && "hash" in settled
|
|
434
|
+
? (0, receipt_js_1.heldReceipt)(settled, client, given)
|
|
435
|
+
: null;
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Tells `onConfirmed` of a step's verified success, once per settlement:
|
|
439
|
+
* only the completion (a run, `completeReviewedStep`, `resumeReviewed`, in
|
|
440
|
+
* any tab) that claims its notice on the hold tells it.
|
|
441
|
+
*/
|
|
442
|
+
async function tellConfirmed(action, handle, call, step, settled, receipt) {
|
|
443
|
+
if (settled?.result === "success" &&
|
|
444
|
+
receipt &&
|
|
445
|
+
(await handle.claimConfirmed(settled)))
|
|
446
|
+
await (0, receipt_js_1.tell)(action.onConfirmed, call, step, receipt);
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* A sent step's settlement by its own reservation, and the receipt its hold
|
|
450
|
+
* verified ({@link heldReceipt}), read again until it reads. Null on `follow`'s
|
|
451
|
+
* timeout or signal, or when the hold cleared without settling it (its exit).
|
|
452
|
+
*/
|
|
453
|
+
async function followSent(handle, client, reserved, follow) {
|
|
454
|
+
const stop = new AbortController();
|
|
455
|
+
const timer = setTimeout(() => stop.abort(), follow.timeoutMs ?? heldWrite_js_1.FOLLOW_MS);
|
|
456
|
+
const signal = follow.signal
|
|
457
|
+
? AbortSignal.any([stop.signal, follow.signal])
|
|
458
|
+
: stop.signal;
|
|
459
|
+
// Every read races the follow's end: a read that answers after it is ignored.
|
|
460
|
+
const ended = new Promise((resolve) => {
|
|
461
|
+
signal.addEventListener("abort", () => resolve(null), { once: true });
|
|
462
|
+
});
|
|
463
|
+
const read = (work) => Promise.race([work, ended]);
|
|
464
|
+
try {
|
|
465
|
+
while (!signal.aborted) {
|
|
466
|
+
const state = await read((0, heldWrite_js_1.followHeldWrite)(handle, client, { signal }));
|
|
467
|
+
if (signal.aborted)
|
|
468
|
+
return null;
|
|
469
|
+
if (state?.status !== "clear" ||
|
|
470
|
+
state.reservation !== reserved ||
|
|
471
|
+
!state.settled ||
|
|
472
|
+
!("hash" in state.settled))
|
|
473
|
+
return null;
|
|
474
|
+
const { settled } = state;
|
|
475
|
+
try {
|
|
476
|
+
const receipt = await read((0, receipt_js_1.heldReceipt)(settled, client));
|
|
477
|
+
return signal.aborted || !receipt ? null : { settled, receipt };
|
|
478
|
+
}
|
|
479
|
+
catch {
|
|
480
|
+
await (0, pause_js_1.pause)(heldWrite_js_1.RECEIPT_RETRY_MS, signal, () => null).catch(() => null);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return null;
|
|
484
|
+
}
|
|
485
|
+
finally {
|
|
486
|
+
clearTimeout(timer);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Completes a sent step (one a run left at its receipt,
|
|
491
|
+
* {@link ReviewedReceiptUnverifiedError}, or a proposal: its step and its
|
|
492
|
+
* `held` call and reservation) once its hold settled that send, as the run
|
|
493
|
+
* itself would have: the saved sequence under `scope` records it, a success
|
|
494
|
+
* is told to `onConfirmed` with the receipt its hold verified (`receipt`,
|
|
495
|
+
* the hold view's, say, when it is that one) and only then acknowledged, the
|
|
496
|
+
* one acknowledgement of a followed step. Returns the settlement and that
|
|
497
|
+
* checked receipt (a failure's too); null until then. A read that fails or disagrees with the hold throws with
|
|
498
|
+
* nothing advanced: call it again. Call it once per settlement:
|
|
499
|
+
* `onConfirmed` is told each time.
|
|
500
|
+
*/
|
|
501
|
+
async function completeReviewedStep(unverified, action, deps, receipt) {
|
|
502
|
+
const { step, held } = unverified;
|
|
503
|
+
if (!held)
|
|
504
|
+
return null;
|
|
505
|
+
const { call, reservation } = held;
|
|
506
|
+
const client = deps.clientFor(call.chainId);
|
|
507
|
+
const handle = (0, writeHold_js_1.openStepHold)(deps.hold, action.account, false, call);
|
|
508
|
+
const state = await handle.state(client);
|
|
509
|
+
if (state.status !== "clear" ||
|
|
510
|
+
state.reservation !== reservation ||
|
|
511
|
+
!state.settled)
|
|
512
|
+
return null;
|
|
513
|
+
const { settled } = state;
|
|
514
|
+
const confirmed = await confirmedReceipt(settled, client, receipt);
|
|
515
|
+
if (action.scope !== undefined) {
|
|
516
|
+
const storage = deps.storage ?? (0, writeRecovery_js_1.createHeldWriteStorage)();
|
|
517
|
+
const { raw, record } = (0, sequence_js_1.readReviewedSequence)(action.scope, action.account, storage);
|
|
518
|
+
if (record?.sending?.step === step &&
|
|
519
|
+
record.sending.reservation === reservation)
|
|
520
|
+
await recordSending(record, settled, storage, raw);
|
|
521
|
+
}
|
|
522
|
+
await tellConfirmed(action, handle, call, step, settled, confirmed);
|
|
523
|
+
if (settled.result === "success")
|
|
524
|
+
await handle.acknowledge(settled);
|
|
525
|
+
return { settled, receipt: confirmed };
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* The hash a wallet returned, even when the site's record of it failed
|
|
529
|
+
* afterwards: the step was sent.
|
|
530
|
+
*/
|
|
531
|
+
function sentHash(error) {
|
|
532
|
+
if (error instanceof contractWrite_js_1.SubmittedContractWriteError)
|
|
533
|
+
return error.hash;
|
|
534
|
+
throw error;
|
|
535
|
+
}
|
|
424
536
|
async function send(action, deps, resuming) {
|
|
425
|
-
const { adapter, clientFor, hold
|
|
537
|
+
const { adapter, clientFor, hold } = deps;
|
|
538
|
+
const onProgress = (progress) => (0, receipt_js_1.tell)(deps.onProgress, progress);
|
|
426
539
|
action.guard?.();
|
|
427
540
|
const { account } = action;
|
|
428
541
|
const calls = [...action.calls];
|
|
@@ -433,14 +546,7 @@ async function send(action, deps, resuming) {
|
|
|
433
546
|
/** Each step's simulation block, read once; a resumed run's prerequisites are long confirmed. */
|
|
434
547
|
const blocks = calls.map((call) => resuming ? undefined : call.simulationBlockNumber);
|
|
435
548
|
/** A site's release callback never stops core's own release. */
|
|
436
|
-
const tellUnsent =
|
|
437
|
-
try {
|
|
438
|
-
await action.onUnsent?.(call, step);
|
|
439
|
-
}
|
|
440
|
-
catch {
|
|
441
|
-
/* The step is released whatever the site's callback does. */
|
|
442
|
-
}
|
|
443
|
-
};
|
|
549
|
+
const tellUnsent = (call, step) => (0, receipt_js_1.tell)(action.onUnsent, call, step);
|
|
444
550
|
const connected = adapter.account();
|
|
445
551
|
if (!connected)
|
|
446
552
|
throw new lineError_js_1.ReviewLineError("Connect a wallet first.");
|
|
@@ -495,20 +601,12 @@ async function send(action, deps, resuming) {
|
|
|
495
601
|
await tellUnsent(call, step);
|
|
496
602
|
throw error;
|
|
497
603
|
}
|
|
498
|
-
// Every step is told; a site's failure to record it never
|
|
499
|
-
const failures = [];
|
|
604
|
+
// Every step is told; a site's failure to record it never changes what was sent.
|
|
500
605
|
for (const [step, call] of calls.entries())
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
});
|
|
506
|
-
}
|
|
507
|
-
catch (error) {
|
|
508
|
-
failures.push(error);
|
|
509
|
-
}
|
|
510
|
-
if (failures.length)
|
|
511
|
-
throw new contractWrite_js_1.SubmittedContractWriteError(hash, failures[0]);
|
|
606
|
+
await (0, receipt_js_1.tell)(action.onSubmitted, call, step, hash, {
|
|
607
|
+
safe: false,
|
|
608
|
+
adopted: false,
|
|
609
|
+
});
|
|
512
610
|
return { status: "done", hashes: [hash], receipts: [] };
|
|
513
611
|
}
|
|
514
612
|
const { scope } = action;
|
|
@@ -549,6 +647,10 @@ async function send(action, deps, resuming) {
|
|
|
549
647
|
if (state.status !== "clear")
|
|
550
648
|
throw new writeHold_js_1.WriteHeldError(state);
|
|
551
649
|
}
|
|
650
|
+
// So is one whose last success nothing showed: a resend may pay twice.
|
|
651
|
+
const away = handles[handles.length - 1].unacknowledgedSuccess();
|
|
652
|
+
if (away)
|
|
653
|
+
throw new writeHold_js_1.WriteHoldUnacknowledgedSuccessError(away);
|
|
552
654
|
/**
|
|
553
655
|
* Each step's latest reservation as the review opened. Another prompt of
|
|
554
656
|
* the same action that reserved meanwhile, whether or not it has settled,
|
|
@@ -621,7 +723,7 @@ async function send(action, deps, resuming) {
|
|
|
621
723
|
if (!sameCall(now, sent[step]))
|
|
622
724
|
throw new lineError_js_1.ReviewLineError(CHANGED);
|
|
623
725
|
});
|
|
624
|
-
const progress = (phase, hash) => onProgress
|
|
726
|
+
const progress = (phase, hash) => onProgress({
|
|
625
727
|
step: 0,
|
|
626
728
|
total: calls.length,
|
|
627
729
|
phase,
|
|
@@ -629,7 +731,8 @@ async function send(action, deps, resuming) {
|
|
|
629
731
|
});
|
|
630
732
|
/** The steps whose `beforeWallet` began. */
|
|
631
733
|
let began = 0;
|
|
632
|
-
const hash = await handles[0]
|
|
734
|
+
const hash = await handles[0]
|
|
735
|
+
.send(client, (gate) => {
|
|
633
736
|
if (generation(handles[0]) !== reviewedGenerations[0]) {
|
|
634
737
|
throw new writeHold_js_1.WriteHoldStaleReviewError();
|
|
635
738
|
}
|
|
@@ -692,19 +795,11 @@ async function send(action, deps, resuming) {
|
|
|
692
795
|
onWriteSubmitted: async (submitted) => {
|
|
693
796
|
gate.afterSubmit(submitted);
|
|
694
797
|
// Every step went: each is told, whatever an earlier callback does.
|
|
695
|
-
const failures = [];
|
|
696
798
|
for (const [step, call] of calls.entries())
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
});
|
|
702
|
-
}
|
|
703
|
-
catch (error) {
|
|
704
|
-
failures.push(error);
|
|
705
|
-
}
|
|
706
|
-
if (failures.length)
|
|
707
|
-
throw failures[0];
|
|
799
|
+
await (0, receipt_js_1.tell)(action.onSubmitted, call, step, submitted, {
|
|
800
|
+
safe: true,
|
|
801
|
+
adopted: false,
|
|
802
|
+
});
|
|
708
803
|
},
|
|
709
804
|
write: async () => {
|
|
710
805
|
const id = await adapter.sendCalls(batched.chainId, sent.map(({ to, data, value }) => ({ to, data, value })));
|
|
@@ -716,7 +811,8 @@ async function send(action, deps, resuming) {
|
|
|
716
811
|
onPhase: (phase) => progress(phase),
|
|
717
812
|
guard: action.guard,
|
|
718
813
|
});
|
|
719
|
-
})
|
|
814
|
+
})
|
|
815
|
+
.catch(sentHash);
|
|
720
816
|
progress("proposed", hash);
|
|
721
817
|
return { status: "proposed", step: 0, safeTxHash: hash, ...signed };
|
|
722
818
|
}
|
|
@@ -765,7 +861,7 @@ async function send(action, deps, resuming) {
|
|
|
765
861
|
const reviewed = sent[step];
|
|
766
862
|
/** This step's index in the whole action. */
|
|
767
863
|
const at = offset + step;
|
|
768
|
-
const progress = (phase, hash) => onProgress
|
|
864
|
+
const progress = (phase, hash) => onProgress({ step: at, total, phase, ...(hash ? { hash } : {}) });
|
|
769
865
|
const unchanged = () => {
|
|
770
866
|
let now;
|
|
771
867
|
try {
|
|
@@ -792,20 +888,20 @@ async function send(action, deps, resuming) {
|
|
|
792
888
|
const done = resuming?.record;
|
|
793
889
|
if (step > 0 || !done?.completed.length)
|
|
794
890
|
return undefined;
|
|
795
|
-
const
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
.
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
891
|
+
const last = done.calls[done.completed.length - 1];
|
|
892
|
+
const hash = done.completed[done.completed.length - 1];
|
|
893
|
+
// Its hold's settlement, while it is still the call's latest, kept
|
|
894
|
+
// the block it verified; else the hash's receipt, canonical and final.
|
|
895
|
+
const held = (0, writeHold_js_1.openStepHold)(hold, account, adapter.isSafe(), last).peek();
|
|
896
|
+
const settled = held.status === "clear" &&
|
|
897
|
+
held.settled &&
|
|
898
|
+
"hash" in held.settled &&
|
|
899
|
+
held.settled.hash.toLowerCase() === hash.toLowerCase()
|
|
900
|
+
? held.settled
|
|
901
|
+
: { result: "success", hash };
|
|
902
|
+
// One try: a block that can't be read or verified now is no block.
|
|
903
|
+
const block = await (0, receipt_js_1.heldBlock)(settled, clientFor(last.chainId)).catch(() => undefined);
|
|
904
|
+
return block && { chainId: last.chainId, ...block };
|
|
809
905
|
};
|
|
810
906
|
const priorBlock = call.dependsOnPrior &&
|
|
811
907
|
prior &&
|
|
@@ -816,7 +912,12 @@ async function send(action, deps, resuming) {
|
|
|
816
912
|
let reserved;
|
|
817
913
|
/** A proposal of exactly this call its Safe already queued, sent in its place. */
|
|
818
914
|
let queued;
|
|
819
|
-
|
|
915
|
+
/** The caller's end of the run, once this run sent a step. */
|
|
916
|
+
const runEnd = hashes.length ? action.follow?.signal : undefined;
|
|
917
|
+
/** The site's failed record of this step's hash: the step was sent, and is held unverified. */
|
|
918
|
+
let unrecorded;
|
|
919
|
+
const hash = await handles[step]
|
|
920
|
+
.send(client, (gate) => {
|
|
820
921
|
// Under the hold's own check of the call, before anything reserves.
|
|
821
922
|
if (generation(handles[step]) !== reviewedGenerations[step]) {
|
|
822
923
|
throw new writeHold_js_1.WriteHoldStaleReviewError();
|
|
@@ -907,6 +1008,10 @@ async function send(action, deps, resuming) {
|
|
|
907
1008
|
}
|
|
908
1009
|
},
|
|
909
1010
|
beforeSend: () => {
|
|
1011
|
+
// The caller ended the run (a reset, an unmount) after it sent a
|
|
1012
|
+
// step: nothing more is sent.
|
|
1013
|
+
if (hashes.length && action.follow?.signal?.aborted)
|
|
1014
|
+
throw new reviewQueue_js_1.TransactionReviewCancelledError();
|
|
910
1015
|
action.assertWriteState?.();
|
|
911
1016
|
unchanged();
|
|
912
1017
|
if (adapter.isSafe() !== safe) {
|
|
@@ -925,16 +1030,32 @@ async function send(action, deps, resuming) {
|
|
|
925
1030
|
// An adopted proposal's nonce lets the hold prove its execution onchain.
|
|
926
1031
|
onWriteSubmitted: async (submitted) => {
|
|
927
1032
|
gate.afterSubmit(submitted, queued?.tx);
|
|
928
|
-
await action.onSubmitted
|
|
1033
|
+
await (0, receipt_js_1.tell)(action.onSubmitted, call, at, submitted, {
|
|
929
1034
|
safe,
|
|
930
1035
|
adopted: !!queued,
|
|
931
1036
|
});
|
|
932
1037
|
},
|
|
933
1038
|
write: async ({ chainId, to, data, value, gas }) => queued?.proposalHash ??
|
|
934
|
-
adapter.sendTransaction({
|
|
1039
|
+
adapter.sendTransaction({
|
|
1040
|
+
chainId,
|
|
1041
|
+
to,
|
|
1042
|
+
data,
|
|
1043
|
+
value,
|
|
1044
|
+
gas,
|
|
1045
|
+
// After a step was sent, the run's end refuses this one, unsent,
|
|
1046
|
+
// as late as the wallet's own last check.
|
|
1047
|
+
...(runEnd ? { signal: runEnd } : {}),
|
|
1048
|
+
}),
|
|
935
1049
|
onPhase: (phase) => progress(phase),
|
|
936
1050
|
guard: action.guard,
|
|
937
1051
|
});
|
|
1052
|
+
})
|
|
1053
|
+
.catch((error) => {
|
|
1054
|
+
// Refused unsent because the caller ended the run: a cancel, not a failure.
|
|
1055
|
+
if (runEnd?.aborted && error instanceof lineError_js_1.WalletNotInvokedError)
|
|
1056
|
+
throw new reviewQueue_js_1.TransactionReviewCancelledError();
|
|
1057
|
+
unrecorded = error;
|
|
1058
|
+
return sentHash(error);
|
|
938
1059
|
});
|
|
939
1060
|
hashes.push(hash);
|
|
940
1061
|
// A later step held under this step's key (the same call, or the same
|
|
@@ -956,21 +1077,56 @@ async function send(action, deps, resuming) {
|
|
|
956
1077
|
progress("proposed", hash);
|
|
957
1078
|
return { status: "proposed", step: at, safeTxHash: hash, ...signed };
|
|
958
1079
|
}
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
.
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
1080
|
+
// From here the step was sent: it ends done, failed as its hold
|
|
1081
|
+
// verified, or unverified with what resumes it, never any other way.
|
|
1082
|
+
const unverified = (cause) => new lineError_js_1.ReviewedReceiptUnverifiedError(at, hash, (0, safeService_js_1.isSafeExecTransaction)(reviewed.data)
|
|
1083
|
+
? messages_js_1.WRITE_HOLD_SAFE_UNCONFIRMED_LINE
|
|
1084
|
+
: undefined, {
|
|
1085
|
+
call,
|
|
1086
|
+
reservation: reserved,
|
|
1087
|
+
// This run's sends, its own last: only the steps before it completed.
|
|
1088
|
+
hashes: journal ? [...journal.completed] : hashes.slice(0, -1),
|
|
1089
|
+
...signed,
|
|
1090
|
+
}, cause === undefined ? {} : { cause });
|
|
1091
|
+
// The site could not record the hash: held as sent, for it to resume.
|
|
1092
|
+
if (unrecorded !== undefined)
|
|
1093
|
+
throw unverified(unrecorded);
|
|
1094
|
+
// Its hold's verified settlement is the only word on how it ended: its
|
|
1095
|
+
// result, its transaction (a speed-up's, when the wallet replaced the
|
|
1096
|
+
// send) and that transaction's receipt in the block the hold verified.
|
|
1097
|
+
// A watcher's receipt only says when to ask.
|
|
1098
|
+
let receipt;
|
|
1099
|
+
let settled;
|
|
1100
|
+
try {
|
|
1101
|
+
progress("receipt", hash);
|
|
1102
|
+
const seen = await (0, receipt_js_1.waitForTrackedReceipt)(client, hash);
|
|
1103
|
+
// Only this send's own reservation's settlement speaks for it: a later
|
|
1104
|
+
// send of the same call or intent may have settled since.
|
|
1105
|
+
settled = await handles[step]
|
|
1106
|
+
.state(client)
|
|
1107
|
+
.then((state) => state.status === "clear" &&
|
|
1108
|
+
reserved !== undefined &&
|
|
1109
|
+
state.reservation === reserved &&
|
|
1110
|
+
state.settled &&
|
|
1111
|
+
"hash" in state.settled
|
|
1112
|
+
? state.settled
|
|
1113
|
+
: undefined)
|
|
1114
|
+
.catch(() => undefined);
|
|
1115
|
+
receipt = settled
|
|
1116
|
+
? await (0, receipt_js_1.heldReceipt)(settled, client, seen).catch(() => undefined)
|
|
1117
|
+
: undefined;
|
|
1118
|
+
if (!receipt && action.follow) {
|
|
1119
|
+
(0, receipt_js_1.tell)(action.follow.onConfirming, at);
|
|
1120
|
+
const ended = await followSent(handles[step], client, reserved, action.follow);
|
|
1121
|
+
({ settled, receipt } = ended ?? { settled, receipt });
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
catch (error) {
|
|
1125
|
+
throw unverified(error);
|
|
1126
|
+
}
|
|
1127
|
+
if (!settled || !receipt)
|
|
1128
|
+
throw unverified();
|
|
1129
|
+
if (settled.result === "failed" && receipt.status === "success") {
|
|
974
1130
|
// It ran, and the hold proved it failed: a Safe's call that failed.
|
|
975
1131
|
if (journal) {
|
|
976
1132
|
delete journal.sending;
|
|
@@ -978,35 +1134,25 @@ async function send(action, deps, resuming) {
|
|
|
978
1134
|
}
|
|
979
1135
|
throw new lineError_js_1.ReviewLineError(messages_js_1.WRITE_HOLD_CALL_FAILED_LINE);
|
|
980
1136
|
}
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
if (receipt.status === "success" &&
|
|
984
|
-
(0, safeService_js_1.isSafeExecTransaction)(reviewed.data) &&
|
|
985
|
-
settled?.result !== "success") {
|
|
986
|
-
throw new lineError_js_1.ReviewLineError(messages_js_1.WRITE_HOLD_SAFE_UNCONFIRMED_LINE);
|
|
987
|
-
}
|
|
1137
|
+
const mined = settled.hash;
|
|
1138
|
+
hashes[hashes.length - 1] = mined;
|
|
988
1139
|
if (receipt.status !== "success") {
|
|
989
1140
|
// It ran and reverted: nothing of it to resume.
|
|
990
1141
|
if (journal) {
|
|
991
1142
|
delete journal.sending;
|
|
992
1143
|
await keep();
|
|
993
1144
|
}
|
|
994
|
-
throw new lineError_js_1.ReviewedCallRevertedError(at,
|
|
1145
|
+
throw new lineError_js_1.ReviewedCallRevertedError(at, mined, receipt);
|
|
995
1146
|
}
|
|
996
1147
|
receipts.push(receipt);
|
|
997
1148
|
if (journal) {
|
|
998
1149
|
delete journal.sending;
|
|
999
|
-
journal.completed.push(
|
|
1150
|
+
journal.completed.push(mined);
|
|
1000
1151
|
await keep();
|
|
1001
1152
|
}
|
|
1002
|
-
|
|
1003
|
-
await action.onConfirmed?.(call, at, receipt);
|
|
1004
|
-
}
|
|
1005
|
-
catch {
|
|
1006
|
-
/* The step went through whatever the site's callback does. */
|
|
1007
|
-
}
|
|
1153
|
+
await tellConfirmed(action, handles[step], call, at, settled, receipt);
|
|
1008
1154
|
}
|
|
1009
|
-
onProgress
|
|
1155
|
+
onProgress({ step: total - 1, total, phase: "done" });
|
|
1010
1156
|
return {
|
|
1011
1157
|
status: "done",
|
|
1012
1158
|
hashes: journal ? [...journal.completed] : hashes,
|