@bananapus/nana-sdk-core 6.1.0 → 6.3.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/dist/cjs/review/confirming.d.ts +8 -0
- package/dist/cjs/review/confirming.d.ts.map +1 -0
- package/dist/cjs/review/confirming.js +11 -0
- package/dist/cjs/review/confirming.js.map +1 -0
- package/dist/cjs/review/heldWrite.d.ts +6 -1
- package/dist/cjs/review/heldWrite.d.ts.map +1 -1
- package/dist/cjs/review/heldWrite.js +13 -6
- package/dist/cjs/review/heldWrite.js.map +1 -1
- package/dist/cjs/review/locks.d.ts +141 -2
- package/dist/cjs/review/locks.d.ts.map +1 -1
- package/dist/cjs/review/locks.js +406 -58
- package/dist/cjs/review/locks.js.map +1 -1
- package/dist/cjs/review/messages.d.ts +16 -0
- package/dist/cjs/review/messages.d.ts.map +1 -1
- package/dist/cjs/review/messages.js +17 -1
- package/dist/cjs/review/messages.js.map +1 -1
- package/dist/cjs/review/react/ownership.d.ts +30 -0
- package/dist/cjs/review/react/ownership.d.ts.map +1 -0
- package/dist/cjs/review/react/ownership.js +27 -0
- package/dist/cjs/review/react/ownership.js.map +1 -0
- package/dist/cjs/review/react/useReviewedRun.d.ts +17 -3
- package/dist/cjs/review/react/useReviewedRun.d.ts.map +1 -1
- package/dist/cjs/review/react/useReviewedRun.js +528 -68
- package/dist/cjs/review/react/useReviewedRun.js.map +1 -1
- package/dist/cjs/review/react/useSavedAttempt.d.ts.map +1 -1
- package/dist/cjs/review/react/useSavedAttempt.js +12 -0
- package/dist/cjs/review/react/useSavedAttempt.js.map +1 -1
- package/dist/cjs/review/relayrSend.d.ts +20 -0
- package/dist/cjs/review/relayrSend.d.ts.map +1 -1
- package/dist/cjs/review/relayrSend.js +150 -105
- package/dist/cjs/review/relayrSend.js.map +1 -1
- package/dist/cjs/review/runStatus.d.ts +6 -2
- package/dist/cjs/review/runStatus.d.ts.map +1 -1
- package/dist/cjs/review/runStatus.js +3 -1
- package/dist/cjs/review/runStatus.js.map +1 -1
- package/dist/cjs/review/safeRelayr.d.ts +12 -2
- package/dist/cjs/review/safeRelayr.d.ts.map +1 -1
- package/dist/cjs/review/safeRelayr.js +226 -156
- package/dist/cjs/review/safeRelayr.js.map +1 -1
- package/dist/cjs/review/savedAttempt.d.ts.map +1 -1
- package/dist/cjs/review/savedAttempt.js +7 -2
- package/dist/cjs/review/savedAttempt.js.map +1 -1
- package/dist/cjs/review/send.d.ts +46 -5
- package/dist/cjs/review/send.d.ts.map +1 -1
- package/dist/cjs/review/send.js +251 -58
- package/dist/cjs/review/send.js.map +1 -1
- package/dist/cjs/review/sequence.d.ts +25 -0
- package/dist/cjs/review/sequence.d.ts.map +1 -1
- package/dist/cjs/review/sequence.js +45 -7
- package/dist/cjs/review/sequence.js.map +1 -1
- package/dist/cjs/review/sign.d.ts +6 -1
- package/dist/cjs/review/sign.d.ts.map +1 -1
- package/dist/cjs/review/sign.js +10 -4
- package/dist/cjs/review/sign.js.map +1 -1
- package/dist/cjs/review/tabState.d.ts +4 -0
- package/dist/cjs/review/tabState.d.ts.map +1 -1
- package/dist/cjs/review/tabState.js +4 -0
- package/dist/cjs/review/tabState.js.map +1 -1
- package/dist/cjs/review/wallet.d.ts +16 -4
- package/dist/cjs/review/wallet.d.ts.map +1 -1
- package/dist/cjs/review/wallet.js +62 -17
- package/dist/cjs/review/wallet.js.map +1 -1
- package/dist/cjs/review/writeHold.d.ts +92 -14
- package/dist/cjs/review/writeHold.d.ts.map +1 -1
- package/dist/cjs/review/writeHold.js +102 -26
- package/dist/cjs/review/writeHold.js.map +1 -1
- package/dist/cjs/review/writeRecovery.d.ts +42 -7
- package/dist/cjs/review/writeRecovery.d.ts.map +1 -1
- package/dist/cjs/review/writeRecovery.js +183 -21
- package/dist/cjs/review/writeRecovery.js.map +1 -1
- package/dist/cjs/testing.d.ts +13 -0
- package/dist/cjs/testing.d.ts.map +1 -1
- package/dist/cjs/testing.js +21 -0
- package/dist/cjs/testing.js.map +1 -1
- package/dist/esm/review/confirming.d.ts +8 -0
- package/dist/esm/review/confirming.d.ts.map +1 -0
- package/dist/esm/review/confirming.js +8 -0
- package/dist/esm/review/confirming.js.map +1 -0
- package/dist/esm/review/heldWrite.d.ts +6 -1
- package/dist/esm/review/heldWrite.d.ts.map +1 -1
- package/dist/esm/review/heldWrite.js +13 -6
- package/dist/esm/review/heldWrite.js.map +1 -1
- package/dist/esm/review/locks.d.ts +141 -2
- package/dist/esm/review/locks.d.ts.map +1 -1
- package/dist/esm/review/locks.js +396 -58
- package/dist/esm/review/locks.js.map +1 -1
- package/dist/esm/review/messages.d.ts +16 -0
- package/dist/esm/review/messages.d.ts.map +1 -1
- package/dist/esm/review/messages.js +16 -0
- package/dist/esm/review/messages.js.map +1 -1
- package/dist/esm/review/react/ownership.d.ts +30 -0
- package/dist/esm/review/react/ownership.d.ts.map +1 -0
- package/dist/esm/review/react/ownership.js +24 -0
- package/dist/esm/review/react/ownership.js.map +1 -0
- package/dist/esm/review/react/useReviewedRun.d.ts +17 -3
- package/dist/esm/review/react/useReviewedRun.d.ts.map +1 -1
- package/dist/esm/review/react/useReviewedRun.js +529 -69
- package/dist/esm/review/react/useReviewedRun.js.map +1 -1
- package/dist/esm/review/react/useSavedAttempt.d.ts.map +1 -1
- package/dist/esm/review/react/useSavedAttempt.js +12 -0
- package/dist/esm/review/react/useSavedAttempt.js.map +1 -1
- package/dist/esm/review/relayrSend.d.ts +20 -0
- package/dist/esm/review/relayrSend.d.ts.map +1 -1
- package/dist/esm/review/relayrSend.js +154 -109
- package/dist/esm/review/relayrSend.js.map +1 -1
- package/dist/esm/review/runStatus.d.ts +6 -2
- package/dist/esm/review/runStatus.d.ts.map +1 -1
- package/dist/esm/review/runStatus.js +3 -1
- package/dist/esm/review/runStatus.js.map +1 -1
- package/dist/esm/review/safeRelayr.d.ts +12 -2
- package/dist/esm/review/safeRelayr.d.ts.map +1 -1
- package/dist/esm/review/safeRelayr.js +226 -156
- package/dist/esm/review/safeRelayr.js.map +1 -1
- package/dist/esm/review/savedAttempt.d.ts.map +1 -1
- package/dist/esm/review/savedAttempt.js +7 -2
- package/dist/esm/review/savedAttempt.js.map +1 -1
- package/dist/esm/review/send.d.ts +46 -5
- package/dist/esm/review/send.d.ts.map +1 -1
- package/dist/esm/review/send.js +252 -59
- package/dist/esm/review/send.js.map +1 -1
- package/dist/esm/review/sequence.d.ts +25 -0
- package/dist/esm/review/sequence.d.ts.map +1 -1
- package/dist/esm/review/sequence.js +43 -7
- package/dist/esm/review/sequence.js.map +1 -1
- package/dist/esm/review/sign.d.ts +6 -1
- package/dist/esm/review/sign.d.ts.map +1 -1
- package/dist/esm/review/sign.js +10 -4
- package/dist/esm/review/sign.js.map +1 -1
- package/dist/esm/review/tabState.d.ts +4 -0
- package/dist/esm/review/tabState.d.ts.map +1 -1
- package/dist/esm/review/tabState.js +4 -0
- package/dist/esm/review/tabState.js.map +1 -1
- package/dist/esm/review/wallet.d.ts +16 -4
- package/dist/esm/review/wallet.d.ts.map +1 -1
- package/dist/esm/review/wallet.js +62 -17
- package/dist/esm/review/wallet.js.map +1 -1
- package/dist/esm/review/writeHold.d.ts +92 -14
- package/dist/esm/review/writeHold.d.ts.map +1 -1
- package/dist/esm/review/writeHold.js +102 -26
- package/dist/esm/review/writeHold.js.map +1 -1
- package/dist/esm/review/writeRecovery.d.ts +42 -7
- package/dist/esm/review/writeRecovery.d.ts.map +1 -1
- package/dist/esm/review/writeRecovery.js +180 -22
- package/dist/esm/review/writeRecovery.js.map +1 -1
- package/dist/esm/testing.d.ts +13 -0
- package/dist/esm/testing.d.ts.map +1 -1
- package/dist/esm/testing.js +20 -0
- package/dist/esm/testing.js.map +1 -1
- package/package.json +1 -1
package/dist/cjs/review/send.js
CHANGED
|
@@ -5,6 +5,8 @@ exports.reviewPlan = reviewPlan;
|
|
|
5
5
|
exports.sendReviewed = sendReviewed;
|
|
6
6
|
exports.resumeReviewed = resumeReviewed;
|
|
7
7
|
exports.completeReviewedStep = completeReviewedStep;
|
|
8
|
+
const locks_js_1 = require("./locks.js");
|
|
9
|
+
const confirming_js_1 = require("./confirming.js");
|
|
8
10
|
const lineError_js_1 = require("./lineError.js");
|
|
9
11
|
const viem_1 = require("viem");
|
|
10
12
|
const confirm_js_1 = require("./confirm.js");
|
|
@@ -389,16 +391,38 @@ async function resumeReviewed(record, action, deps) {
|
|
|
389
391
|
const { settled } = state;
|
|
390
392
|
// Read before anything advances: a failed read leaves the step to resume again.
|
|
391
393
|
const receipt = await confirmedReceipt(settled, deps.clientFor(call.chainId));
|
|
392
|
-
// This sequence's own step:
|
|
393
|
-
//
|
|
394
|
-
|
|
395
|
-
|
|
394
|
+
// This sequence's own step: told, recorded, and only then acknowledged,
|
|
395
|
+
// so it is never offered again. Its notice not delivered yet, it stays
|
|
396
|
+
// held at its receipt, acknowledged by none, for a completion to tell.
|
|
397
|
+
let kept = expected;
|
|
398
|
+
const outcome = outcomeOf(handle, reservation, {
|
|
399
|
+
account: saved.account,
|
|
400
|
+
step,
|
|
401
|
+
call,
|
|
402
|
+
prior: [...saved.completed],
|
|
403
|
+
...(saved.signatures ? { signatures: saved.signatures } : {}),
|
|
404
|
+
});
|
|
405
|
+
const ended = await endStep(action, handle, outcome, settled, receipt, async () => {
|
|
406
|
+
kept = await recordSending(saved, settled, storage, expected);
|
|
407
|
+
});
|
|
408
|
+
if (!ended)
|
|
409
|
+
throw new lineError_js_1.ReviewedReceiptUnverifiedError(step, settled.hash, undefined, {
|
|
410
|
+
call: outcome.call,
|
|
411
|
+
reservation,
|
|
412
|
+
hashes: [...outcome.prior],
|
|
413
|
+
...signedBy(outcome),
|
|
414
|
+
});
|
|
396
415
|
if (settled?.result === "success")
|
|
397
416
|
await handle.acknowledge(settled);
|
|
398
417
|
if (kept === null) {
|
|
399
418
|
const total = saved.calls.length;
|
|
400
419
|
(0, receipt_js_1.tell)(deps.onProgress, { step: total - 1, total, phase: "done" });
|
|
401
|
-
return {
|
|
420
|
+
return {
|
|
421
|
+
status: "done",
|
|
422
|
+
hashes: hashesThrough(outcome, settled),
|
|
423
|
+
receipts: [],
|
|
424
|
+
...signedBy(outcome),
|
|
425
|
+
};
|
|
402
426
|
}
|
|
403
427
|
expected = kept;
|
|
404
428
|
}
|
|
@@ -437,14 +461,87 @@ async function confirmedReceipt(settled, client, given) {
|
|
|
437
461
|
/**
|
|
438
462
|
* Tells `onConfirmed` of a step's verified success, once per settlement:
|
|
439
463
|
* only the completion (a run, `completeReviewedStep`, `resumeReviewed`, in
|
|
440
|
-
* any tab) that claims its notice on the hold tells it.
|
|
464
|
+
* any tab) that claims its notice on the hold tells it. The claim is made
|
|
465
|
+
* for good once told, and given back if the site never gets it, so a later
|
|
466
|
+
* completion tells it.
|
|
441
467
|
*/
|
|
442
468
|
async function tellConfirmed(action, handle, call, step, settled, receipt) {
|
|
443
|
-
if (settled?.result
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
469
|
+
if (settled?.result !== "success" || !receipt)
|
|
470
|
+
return "delivered";
|
|
471
|
+
const claimant = globalThis.crypto.randomUUID();
|
|
472
|
+
if (!(await handle.claimConfirmed(settled, claimant)))
|
|
473
|
+
// Another completion's: delivered, or not yet.
|
|
474
|
+
return (await handle.confirmation(settled)) === "delivered"
|
|
475
|
+
? "delivered"
|
|
476
|
+
: "pending";
|
|
477
|
+
// Renewed while this delivery runs (kept for a lock too), so only a claim
|
|
478
|
+
// whose tab closed or crashed lapses; ended only by this claimant.
|
|
479
|
+
const renewal = setInterval(() => void handle.claimConfirmed(settled, claimant).catch(() => undefined), confirming_js_1.CONFIRMING_RENEW_MS);
|
|
480
|
+
let delivery = "pending";
|
|
481
|
+
const end = async (delivered) => {
|
|
482
|
+
clearInterval(renewal);
|
|
483
|
+
await handle.settleConfirmed(settled, delivered, claimant);
|
|
484
|
+
};
|
|
485
|
+
try {
|
|
486
|
+
const told = await tellKept(action, () => action.onConfirmed?.(call, step, receipt), async (applied) => {
|
|
487
|
+
delivery = applied ? "delivered" : "undelivered";
|
|
488
|
+
await end(applied);
|
|
489
|
+
});
|
|
490
|
+
if (!told)
|
|
491
|
+
return delivery;
|
|
492
|
+
await end(true);
|
|
493
|
+
return "delivered";
|
|
494
|
+
}
|
|
495
|
+
catch (error) {
|
|
496
|
+
clearInterval(renewal);
|
|
497
|
+
throw error;
|
|
498
|
+
}
|
|
447
499
|
}
|
|
500
|
+
/**
|
|
501
|
+
* Ends a settled step, the one way every completion does (a run, a resume,
|
|
502
|
+
* `completeReviewedStep`): its `onConfirmed` told with its outcome's call
|
|
503
|
+
* and step, and only once delivered is it recorded done (`record`, its
|
|
504
|
+
* reservation leaving the sequence's journal). Until then the step stays
|
|
505
|
+
* held there, so a later completion or resume tells it before any step
|
|
506
|
+
* after it is sent. False while undelivered.
|
|
507
|
+
*/
|
|
508
|
+
async function endStep(action, handle, outcome, settled, receipt, record) {
|
|
509
|
+
if ((await tellConfirmed(action, handle, outcome.call, outcome.step, settled, receipt)) !== "delivered")
|
|
510
|
+
return false;
|
|
511
|
+
await record();
|
|
512
|
+
return true;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* A sent step's outcome as its run saved it on the hold with `reservation`
|
|
516
|
+
* ({@link ReviewedOutcome}), else `handed` (what its caller has: a hold
|
|
517
|
+
* that saved none, or an older version's).
|
|
518
|
+
*/
|
|
519
|
+
const outcomeOf = (handle, reservation, handed) => (reservation === undefined
|
|
520
|
+
? undefined
|
|
521
|
+
: (0, sequence_js_1.decodeOutcome)(handle.outcomeOf(reservation))) ?? handed;
|
|
522
|
+
/** The action's hashes through `outcome`'s step, as `settled` ended it. */
|
|
523
|
+
const hashesThrough = (outcome, settled) => settled?.result === "success" && "hash" in settled
|
|
524
|
+
? [...outcome.prior, settled.hash]
|
|
525
|
+
: [...outcome.prior];
|
|
526
|
+
/** The outcome's signatures, as a result spreads them. */
|
|
527
|
+
const signedBy = ({ signatures }) => signatures ? { signatures: [...signatures] } : {};
|
|
528
|
+
/**
|
|
529
|
+
* Tells a site what the wallet answered, under its `locks`: refused for a
|
|
530
|
+
* lost one, kept for a fresh lock ({@link keepOutcome}, `settled` told
|
|
531
|
+
* whether it was applied in the end), or dropped when it can't be kept
|
|
532
|
+
* (`settled` told false). Any other failure is logged and never changes
|
|
533
|
+
* what was sent. False when the outcome was only kept, not told.
|
|
534
|
+
*/
|
|
535
|
+
const tellKept = async ({ locks, attemptScoped }, run, settled) => {
|
|
536
|
+
let kept = false;
|
|
537
|
+
await (0, receipt_js_1.tell)(() => (0, locks_js_1.keepOutcome)(locks, run, attemptScoped ? run : undefined, settled).then((applied) => void (kept = !applied), async (error) => {
|
|
538
|
+
if (error?.code !== "LOCK_LOST")
|
|
539
|
+
throw error;
|
|
540
|
+
kept = true;
|
|
541
|
+
await settled?.(false);
|
|
542
|
+
}));
|
|
543
|
+
return !kept;
|
|
544
|
+
};
|
|
448
545
|
/**
|
|
449
546
|
* A sent step's settlement by its own reservation, and the receipt its hold
|
|
450
547
|
* verified ({@link heldReceipt}), read again until it reads. Null on `follow`'s
|
|
@@ -463,7 +560,10 @@ async function followSent(handle, client, reserved, follow) {
|
|
|
463
560
|
const read = (work) => Promise.race([work, ended]);
|
|
464
561
|
try {
|
|
465
562
|
while (!signal.aborted) {
|
|
466
|
-
const state = await read((0, heldWrite_js_1.followHeldWrite)(handle, client, {
|
|
563
|
+
const state = await read((0, heldWrite_js_1.followHeldWrite)(handle, client, {
|
|
564
|
+
signal,
|
|
565
|
+
...(reserved ? { reservation: reserved } : {}),
|
|
566
|
+
}));
|
|
467
567
|
if (signal.aborted)
|
|
468
568
|
return null;
|
|
469
569
|
if (state?.status !== "clear" ||
|
|
@@ -496,33 +596,72 @@ async function followSent(handle, client, reserved, follow) {
|
|
|
496
596
|
* one acknowledgement of a followed step. Returns the settlement and that
|
|
497
597
|
* checked receipt (a failure's too); null until then. A read that fails or disagrees with the hold throws with
|
|
498
598
|
* nothing advanced: call it again. Call it once per settlement:
|
|
499
|
-
* `onConfirmed` is told each time.
|
|
599
|
+
* `onConfirmed` is told each time. Its reservation's own saved settlement
|
|
600
|
+
* completes it after a later reservation of the call replaced it. Once
|
|
601
|
+
* `signal` aborts (the run that showed it is gone) it returns null, leaving
|
|
602
|
+
* the journal and `onConfirmed` to the run that resumes it. With
|
|
603
|
+
* `acknowledge` false it acknowledges nothing: the caller acknowledges the
|
|
604
|
+
* success once it has shown it (`handle.acknowledge`), so a success it
|
|
605
|
+
* never showed still warns the next run. `undelivered` says `onConfirmed`
|
|
606
|
+
* was kept for a lost lock and dropped: nothing is acknowledged, and a later
|
|
607
|
+
* completion (under the same or a fresh lock) tells it once.
|
|
500
608
|
*/
|
|
501
|
-
async function completeReviewedStep(unverified, action, deps, receipt) {
|
|
609
|
+
async function completeReviewedStep(unverified, action, deps, receipt, signal, acknowledge = true) {
|
|
502
610
|
const { step, held } = unverified;
|
|
503
|
-
if (!held)
|
|
611
|
+
if (!held || signal?.aborted)
|
|
504
612
|
return null;
|
|
505
613
|
const { call, reservation } = held;
|
|
506
614
|
const client = deps.clientFor(call.chainId);
|
|
507
615
|
const handle = (0, writeHold_js_1.openStepHold)(deps.hold, action.account, false, call);
|
|
508
616
|
const state = await handle.state(client);
|
|
509
|
-
|
|
510
|
-
state.
|
|
511
|
-
|
|
617
|
+
const settled = (state.status === "clear" && state.reservation === reservation
|
|
618
|
+
? state.settled
|
|
619
|
+
: undefined) ??
|
|
620
|
+
(reservation === undefined ? undefined : handle.settlementOf(reservation));
|
|
621
|
+
if (!settled)
|
|
512
622
|
return null;
|
|
513
|
-
const { settled } = state;
|
|
514
623
|
const confirmed = await confirmedReceipt(settled, client, receipt);
|
|
515
|
-
if (
|
|
624
|
+
if (signal?.aborted)
|
|
625
|
+
return null;
|
|
626
|
+
const outcome = outcomeOf(handle, reservation, {
|
|
627
|
+
account: action.account,
|
|
628
|
+
step,
|
|
629
|
+
call,
|
|
630
|
+
prior: [...(held.hashes ?? [])],
|
|
631
|
+
...(held.signatures ? { signatures: held.signatures } : {}),
|
|
632
|
+
});
|
|
633
|
+
const ended = await endStep(action, handle, outcome, settled, confirmed, async () => {
|
|
634
|
+
if (action.scope === undefined)
|
|
635
|
+
return;
|
|
516
636
|
const storage = deps.storage ?? (0, writeRecovery_js_1.createHeldWriteStorage)();
|
|
517
|
-
const
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
637
|
+
const scope = action.scope;
|
|
638
|
+
// Its journal entry by the reservation it saved (by the step its
|
|
639
|
+
// outcome saved, without one), never by the index of the action that
|
|
640
|
+
// completes it: a refreshed action's calls may be fewer.
|
|
641
|
+
const sending = () => {
|
|
642
|
+
const read = (0, sequence_js_1.readReviewedSequence)(scope, action.account, storage);
|
|
643
|
+
const saved = read.record?.sending;
|
|
644
|
+
return saved &&
|
|
645
|
+
saved.reservation === reservation &&
|
|
646
|
+
(reservation !== undefined || saved.step === outcome.step)
|
|
647
|
+
? read
|
|
648
|
+
: null;
|
|
649
|
+
};
|
|
650
|
+
const read = sending();
|
|
651
|
+
if (!read)
|
|
652
|
+
return;
|
|
653
|
+
// Another completion recording it first leaves nothing to record.
|
|
654
|
+
await recordSending(read.record, settled, storage, read.raw).catch((error) => {
|
|
655
|
+
if (sending())
|
|
656
|
+
throw error;
|
|
657
|
+
});
|
|
658
|
+
});
|
|
659
|
+
const done = { settled, receipt: confirmed, ...signedBy(outcome) };
|
|
660
|
+
if (!ended)
|
|
661
|
+
return { ...done, undelivered: true, hashes: [] };
|
|
662
|
+
if (acknowledge && settled.result === "success")
|
|
524
663
|
await handle.acknowledge(settled);
|
|
525
|
-
return {
|
|
664
|
+
return { ...done, hashes: hashesThrough(outcome, settled) };
|
|
526
665
|
}
|
|
527
666
|
/**
|
|
528
667
|
* The hash a wallet returned, even when the site's record of it failed
|
|
@@ -545,8 +684,21 @@ async function send(action, deps, resuming) {
|
|
|
545
684
|
const sent = snapshots.map(({ sent }) => sent);
|
|
546
685
|
/** Each step's simulation block, read once; a resumed run's prerequisites are long confirmed. */
|
|
547
686
|
const blocks = calls.map((call) => resuming ? undefined : call.simulationBlockNumber);
|
|
548
|
-
/**
|
|
549
|
-
|
|
687
|
+
/**
|
|
688
|
+
* Tell the site its steps from `from` were not sent, each only while every
|
|
689
|
+
* one of its locks is still this tab's, read fresh right before that
|
|
690
|
+
* step's callback (an earlier callback's await may have outlived the
|
|
691
|
+
* lease): once one was lost, the lock's new owner owns the site's journal,
|
|
692
|
+
* whatever ended the attempt. A site's release callback never stops core's
|
|
693
|
+
* own release.
|
|
694
|
+
*/
|
|
695
|
+
const tellUnsent = async (steps, from) => {
|
|
696
|
+
for (const [index, call] of steps.entries())
|
|
697
|
+
await tellKept(action, async () => {
|
|
698
|
+
await (0, locks_js_1.assertLocksHeld)(action.locks);
|
|
699
|
+
await action.onUnsent?.(call, from + index);
|
|
700
|
+
});
|
|
701
|
+
};
|
|
550
702
|
const connected = adapter.account();
|
|
551
703
|
if (!connected)
|
|
552
704
|
throw new lineError_js_1.ReviewLineError("Connect a wallet first.");
|
|
@@ -581,32 +733,34 @@ async function send(action, deps, resuming) {
|
|
|
581
733
|
try {
|
|
582
734
|
for (const [step, call] of calls.entries()) {
|
|
583
735
|
began += 1;
|
|
736
|
+
// The site's own record before the wallet: never under a lost lock.
|
|
737
|
+
await (0, locks_js_1.assertLocksHeld)(action.locks);
|
|
584
738
|
await action.beforeWallet?.(call, step);
|
|
585
739
|
}
|
|
740
|
+
await (0, locks_js_1.assertLocksHeld)(action.locks);
|
|
586
741
|
// The site's hooks may have awaited: the gates once more, right before the wallet.
|
|
587
742
|
action.guard?.();
|
|
588
743
|
action.assertWriteState?.();
|
|
589
744
|
if (adapter.account()?.toLowerCase() !== account.toLowerCase())
|
|
590
745
|
throw new lineError_js_1.ReviewLineError(ACCOUNT_CHANGED);
|
|
591
746
|
submitting = true;
|
|
592
|
-
hash = await adapter.submitToReviewer({
|
|
593
|
-
account,
|
|
594
|
-
calls: sent.map((call) => ({ ...call })),
|
|
595
|
-
});
|
|
747
|
+
hash = await adapter.submitToReviewer({ account, calls: sent.map((call) => ({ ...call })) }, { fence: () => (0, locks_js_1.assertLocksHeld)(action.locks) });
|
|
596
748
|
}
|
|
597
749
|
catch (error) {
|
|
598
|
-
// Only the site's own refusal or an explicit rejection
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
750
|
+
// Only the site's own refusal, the adapter's or an explicit rejection
|
|
751
|
+
// proves nothing was sent.
|
|
752
|
+
if (!submitting ||
|
|
753
|
+
error instanceof lineError_js_1.WalletNotInvokedError ||
|
|
754
|
+
(0, contractWrite_js_1.isDefiniteWalletRejection)(error))
|
|
755
|
+
await tellUnsent(calls.slice(0, began), 0);
|
|
602
756
|
throw error;
|
|
603
757
|
}
|
|
604
758
|
// Every step is told; a site's failure to record it never changes what was sent.
|
|
605
759
|
for (const [step, call] of calls.entries())
|
|
606
|
-
await (
|
|
760
|
+
await tellKept(action, () => action.onSubmitted?.(call, step, hash, {
|
|
607
761
|
safe: false,
|
|
608
762
|
adopted: false,
|
|
609
|
-
});
|
|
763
|
+
}));
|
|
610
764
|
return { status: "done", hashes: [hash], receipts: [] };
|
|
611
765
|
}
|
|
612
766
|
const { scope } = action;
|
|
@@ -707,7 +861,7 @@ async function send(action, deps, resuming) {
|
|
|
707
861
|
});
|
|
708
862
|
};
|
|
709
863
|
signed = {
|
|
710
|
-
signatures: await (0, sign_js_1.signPrepared)(prepared, account, adapter, stillReviewed),
|
|
864
|
+
signatures: await (0, sign_js_1.signPrepared)(prepared, account, adapter, stillReviewed, () => (0, locks_js_1.assertLocksHeld)(action.locks), () => (0, locks_js_1.assertLocksHeld)(action.locks)),
|
|
711
865
|
};
|
|
712
866
|
}
|
|
713
867
|
if (batched) {
|
|
@@ -738,9 +892,10 @@ async function send(action, deps, resuming) {
|
|
|
738
892
|
}
|
|
739
893
|
const released = async () => {
|
|
740
894
|
gate.onRejected();
|
|
741
|
-
|
|
742
|
-
await tellUnsent(call, step);
|
|
895
|
+
await tellUnsent(calls.slice(0, began), 0);
|
|
743
896
|
};
|
|
897
|
+
/** Every lock is still this tab's: the hold's and the site's. */
|
|
898
|
+
const fence = () => (0, locks_js_1.assertLocksHeld)([gate, ...(action.locks ?? [])]);
|
|
744
899
|
return (0, contractWrite_js_1.submitReviewedContractWrite)({
|
|
745
900
|
request: batched,
|
|
746
901
|
expectedAccount: account,
|
|
@@ -768,12 +923,23 @@ async function send(action, deps, resuming) {
|
|
|
768
923
|
return sending;
|
|
769
924
|
},
|
|
770
925
|
beforeWrite: async () => {
|
|
771
|
-
await gate.beforeSend()
|
|
926
|
+
await gate.beforeSend(undefined, (0, sequence_js_1.encodeOutcome)({
|
|
927
|
+
account,
|
|
928
|
+
step: calls.length - 1,
|
|
929
|
+
call: batched,
|
|
930
|
+
prior: [],
|
|
931
|
+
...signed,
|
|
932
|
+
}));
|
|
772
933
|
try {
|
|
773
934
|
for (const [step, call] of calls.entries()) {
|
|
774
935
|
began = step + 1;
|
|
936
|
+
// The site's own record before the wallet: never under a lost lock.
|
|
937
|
+
await (0, locks_js_1.assertLocksHeld)(action.locks);
|
|
775
938
|
await action.beforeWallet?.(call, step);
|
|
776
939
|
}
|
|
940
|
+
// Core's own check before the adapter, which fences again as
|
|
941
|
+
// the last await before the wallet.
|
|
942
|
+
await fence();
|
|
777
943
|
}
|
|
778
944
|
catch (error) {
|
|
779
945
|
await released();
|
|
@@ -796,13 +962,13 @@ async function send(action, deps, resuming) {
|
|
|
796
962
|
gate.afterSubmit(submitted);
|
|
797
963
|
// Every step went: each is told, whatever an earlier callback does.
|
|
798
964
|
for (const [step, call] of calls.entries())
|
|
799
|
-
await (
|
|
965
|
+
await tellKept(action, () => action.onSubmitted?.(call, step, submitted, {
|
|
800
966
|
safe: true,
|
|
801
967
|
adopted: false,
|
|
802
|
-
});
|
|
968
|
+
}));
|
|
803
969
|
},
|
|
804
970
|
write: async () => {
|
|
805
|
-
const id = await adapter.sendCalls(batched.chainId, sent.map(({ to, data, value }) => ({ to, data, value })));
|
|
971
|
+
const id = await adapter.sendCalls(batched.chainId, sent.map(({ to, data, value }) => ({ to, data, value })), { fence });
|
|
806
972
|
// A Safe app answers with the proposal's safeTxHash; anything else can't be followed.
|
|
807
973
|
if (typeof id !== "string" || !/^0x[0-9a-fA-F]{64}$/.test(id))
|
|
808
974
|
throw new lineError_js_1.ReviewLineError(exports.SAFE_BATCH_UNFOLLOWABLE_LINE);
|
|
@@ -835,6 +1001,7 @@ async function send(action, deps, resuming) {
|
|
|
835
1001
|
...snapshots[step].sent,
|
|
836
1002
|
})),
|
|
837
1003
|
completed: [],
|
|
1004
|
+
...signed,
|
|
838
1005
|
};
|
|
839
1006
|
// Refused when another window changed it meanwhile.
|
|
840
1007
|
expected = await (0, sequence_js_1.saveReviewedSequence)(journal, storage, expected);
|
|
@@ -855,6 +1022,11 @@ async function send(action, deps, resuming) {
|
|
|
855
1022
|
}
|
|
856
1023
|
};
|
|
857
1024
|
const hashes = [];
|
|
1025
|
+
// A resumed run shows the signatures its first run signed.
|
|
1026
|
+
if (journal?.signatures)
|
|
1027
|
+
signed = { signatures: journal.signatures };
|
|
1028
|
+
/** The last step's outcome, as its hold keeps it, and its hashes: the done result's source. */
|
|
1029
|
+
let last;
|
|
858
1030
|
const receipts = [];
|
|
859
1031
|
const total = offset + calls.length;
|
|
860
1032
|
for (const [step, call] of calls.entries()) {
|
|
@@ -916,6 +1088,14 @@ async function send(action, deps, resuming) {
|
|
|
916
1088
|
const runEnd = hashes.length ? action.follow?.signal : undefined;
|
|
917
1089
|
/** The site's failed record of this step's hash: the step was sent, and is held unverified. */
|
|
918
1090
|
let unrecorded;
|
|
1091
|
+
/** What this step's run shows, saved with its reservation. */
|
|
1092
|
+
const outcome = {
|
|
1093
|
+
account,
|
|
1094
|
+
step: at,
|
|
1095
|
+
call,
|
|
1096
|
+
prior: journal ? [...journal.completed] : [...hashes],
|
|
1097
|
+
...signed,
|
|
1098
|
+
};
|
|
919
1099
|
const hash = await handles[step]
|
|
920
1100
|
.send(client, (gate) => {
|
|
921
1101
|
// Under the hold's own check of the call, before anything reserves.
|
|
@@ -929,8 +1109,10 @@ async function send(action, deps, resuming) {
|
|
|
929
1109
|
delete journal.sending;
|
|
930
1110
|
await keep();
|
|
931
1111
|
}
|
|
932
|
-
await tellUnsent(call, at);
|
|
1112
|
+
await tellUnsent([call], at);
|
|
933
1113
|
};
|
|
1114
|
+
/** Every lock is still this tab's: the hold's and the site's. */
|
|
1115
|
+
const fence = () => (0, locks_js_1.assertLocksHeld)([gate, ...(action.locks ?? [])]);
|
|
934
1116
|
return (0, contractWrite_js_1.submitReviewedContractWrite)({
|
|
935
1117
|
request: reviewed,
|
|
936
1118
|
expectedAccount: account,
|
|
@@ -983,7 +1165,7 @@ async function send(action, deps, resuming) {
|
|
|
983
1165
|
},
|
|
984
1166
|
beforeWrite: async () => {
|
|
985
1167
|
// An adopted proposal is held as the call it runs.
|
|
986
|
-
await gate.beforeSend(queued?.call);
|
|
1168
|
+
await gate.beforeSend(queued?.call, (0, sequence_js_1.encodeOutcome)(outcome));
|
|
987
1169
|
reserved = handles[step].peek().reservation;
|
|
988
1170
|
if (journal)
|
|
989
1171
|
try {
|
|
@@ -1000,7 +1182,12 @@ async function send(action, deps, resuming) {
|
|
|
1000
1182
|
throw error;
|
|
1001
1183
|
}
|
|
1002
1184
|
try {
|
|
1185
|
+
// The site's own record before the wallet: never under a lost lock.
|
|
1186
|
+
await (0, locks_js_1.assertLocksHeld)(action.locks);
|
|
1003
1187
|
await action.beforeWallet?.(call, at);
|
|
1188
|
+
// Core's own check before the adapter, which fences again as
|
|
1189
|
+
// the last await before the wallet.
|
|
1190
|
+
await fence();
|
|
1004
1191
|
}
|
|
1005
1192
|
catch (error) {
|
|
1006
1193
|
await released();
|
|
@@ -1030,10 +1217,10 @@ async function send(action, deps, resuming) {
|
|
|
1030
1217
|
// An adopted proposal's nonce lets the hold prove its execution onchain.
|
|
1031
1218
|
onWriteSubmitted: async (submitted) => {
|
|
1032
1219
|
gate.afterSubmit(submitted, queued?.tx);
|
|
1033
|
-
await (
|
|
1220
|
+
await tellKept(action, () => action.onSubmitted?.(call, at, submitted, {
|
|
1034
1221
|
safe,
|
|
1035
1222
|
adopted: !!queued,
|
|
1036
|
-
});
|
|
1223
|
+
}));
|
|
1037
1224
|
},
|
|
1038
1225
|
write: async ({ chainId, to, data, value, gas }) => queued?.proposalHash ??
|
|
1039
1226
|
adapter.sendTransaction({
|
|
@@ -1045,6 +1232,7 @@ async function send(action, deps, resuming) {
|
|
|
1045
1232
|
// After a step was sent, the run's end refuses this one, unsent,
|
|
1046
1233
|
// as late as the wallet's own last check.
|
|
1047
1234
|
...(runEnd ? { signal: runEnd } : {}),
|
|
1235
|
+
fence,
|
|
1048
1236
|
}),
|
|
1049
1237
|
onPhase: (phase) => progress(phase),
|
|
1050
1238
|
guard: action.guard,
|
|
@@ -1079,14 +1267,14 @@ async function send(action, deps, resuming) {
|
|
|
1079
1267
|
}
|
|
1080
1268
|
// From here the step was sent: it ends done, failed as its hold
|
|
1081
1269
|
// verified, or unverified with what resumes it, never any other way.
|
|
1270
|
+
/** `completed`: this step's hash already recorded as completed. */
|
|
1082
1271
|
const unverified = (cause) => new lineError_js_1.ReviewedReceiptUnverifiedError(at, hash, (0, safeService_js_1.isSafeExecTransaction)(reviewed.data)
|
|
1083
1272
|
? messages_js_1.WRITE_HOLD_SAFE_UNCONFIRMED_LINE
|
|
1084
1273
|
: undefined, {
|
|
1085
1274
|
call,
|
|
1086
1275
|
reservation: reserved,
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
...signed,
|
|
1276
|
+
hashes: [...outcome.prior],
|
|
1277
|
+
...signedBy(outcome),
|
|
1090
1278
|
}, cause === undefined ? {} : { cause });
|
|
1091
1279
|
// The site could not record the hash: held as sent, for it to resume.
|
|
1092
1280
|
if (unrecorded !== undefined)
|
|
@@ -1145,19 +1333,24 @@ async function send(action, deps, resuming) {
|
|
|
1145
1333
|
throw new lineError_js_1.ReviewedCallRevertedError(at, mined, receipt);
|
|
1146
1334
|
}
|
|
1147
1335
|
receipts.push(receipt);
|
|
1148
|
-
|
|
1336
|
+
// Its notice not delivered yet: held at its receipt for its completion.
|
|
1337
|
+
const ended = await endStep(action, handles[step], outcome, settled, receipt, async () => {
|
|
1338
|
+
if (!journal)
|
|
1339
|
+
return;
|
|
1149
1340
|
delete journal.sending;
|
|
1150
1341
|
journal.completed.push(mined);
|
|
1151
1342
|
await keep();
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1343
|
+
});
|
|
1344
|
+
if (!ended)
|
|
1345
|
+
throw unverified();
|
|
1346
|
+
last = { outcome, hashes: hashesThrough(outcome, settled) };
|
|
1154
1347
|
}
|
|
1155
1348
|
onProgress({ step: total - 1, total, phase: "done" });
|
|
1156
1349
|
return {
|
|
1157
1350
|
status: "done",
|
|
1158
|
-
hashes:
|
|
1351
|
+
hashes: last.hashes,
|
|
1159
1352
|
receipts,
|
|
1160
|
-
...
|
|
1353
|
+
...signedBy(last.outcome),
|
|
1161
1354
|
};
|
|
1162
1355
|
}
|
|
1163
1356
|
//# sourceMappingURL=send.js.map
|