@bananapus/nana-sdk-core 2.38.2 → 2.40.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/heldWrite.d.ts +113 -0
- package/dist/cjs/review/heldWrite.d.ts.map +1 -0
- package/dist/cjs/review/heldWrite.js +569 -0
- package/dist/cjs/review/heldWrite.js.map +1 -0
- package/dist/cjs/review/index.d.ts +2 -0
- package/dist/cjs/review/index.d.ts.map +1 -1
- package/dist/cjs/review/index.js +2 -0
- package/dist/cjs/review/index.js.map +1 -1
- package/dist/cjs/review/messages.d.ts +30 -0
- package/dist/cjs/review/messages.d.ts.map +1 -1
- package/dist/cjs/review/messages.js +34 -1
- package/dist/cjs/review/messages.js.map +1 -1
- package/dist/cjs/review/react/HeldWritesNotice.d.ts +11 -0
- package/dist/cjs/review/react/HeldWritesNotice.d.ts.map +1 -0
- package/dist/cjs/review/react/HeldWritesNotice.js +22 -0
- package/dist/cjs/review/react/HeldWritesNotice.js.map +1 -0
- package/dist/cjs/review/react/index.d.ts +5 -0
- package/dist/cjs/review/react/index.d.ts.map +1 -0
- package/dist/cjs/review/react/index.js +21 -0
- package/dist/cjs/review/react/index.js.map +1 -0
- package/dist/cjs/review/react/useHeldWrite.d.ts +63 -0
- package/dist/cjs/review/react/useHeldWrite.d.ts.map +1 -0
- package/dist/cjs/review/react/useHeldWrite.js +107 -0
- package/dist/cjs/review/react/useHeldWrite.js.map +1 -0
- package/dist/cjs/review/react/useHeldWrites.d.ts +40 -0
- package/dist/cjs/review/react/useHeldWrites.d.ts.map +1 -0
- package/dist/cjs/review/react/useHeldWrites.js +95 -0
- package/dist/cjs/review/react/useHeldWrites.js.map +1 -0
- package/dist/cjs/review/react/useSavedAttempt.d.ts +54 -0
- package/dist/cjs/review/react/useSavedAttempt.d.ts.map +1 -0
- package/dist/cjs/review/react/useSavedAttempt.js +105 -0
- package/dist/cjs/review/react/useSavedAttempt.js.map +1 -0
- package/dist/cjs/review/savedAttempt.d.ts +180 -0
- package/dist/cjs/review/savedAttempt.d.ts.map +1 -0
- package/dist/cjs/review/savedAttempt.js +527 -0
- package/dist/cjs/review/savedAttempt.js.map +1 -0
- package/dist/cjs/review/writeHold.d.ts +94 -2
- package/dist/cjs/review/writeHold.d.ts.map +1 -1
- package/dist/cjs/review/writeHold.js +284 -43
- package/dist/cjs/review/writeHold.js.map +1 -1
- package/dist/cjs/review/writeRecovery.d.ts +58 -0
- package/dist/cjs/review/writeRecovery.d.ts.map +1 -1
- package/dist/cjs/review/writeRecovery.js +161 -2
- package/dist/cjs/review/writeRecovery.js.map +1 -1
- package/dist/esm/review/heldWrite.d.ts +113 -0
- package/dist/esm/review/heldWrite.d.ts.map +1 -0
- package/dist/esm/review/heldWrite.js +562 -0
- package/dist/esm/review/heldWrite.js.map +1 -0
- package/dist/esm/review/index.d.ts +2 -0
- package/dist/esm/review/index.d.ts.map +1 -1
- package/dist/esm/review/index.js +2 -0
- package/dist/esm/review/index.js.map +1 -1
- package/dist/esm/review/messages.d.ts +30 -0
- package/dist/esm/review/messages.d.ts.map +1 -1
- package/dist/esm/review/messages.js +32 -0
- package/dist/esm/review/messages.js.map +1 -1
- package/dist/esm/review/react/HeldWritesNotice.d.ts +11 -0
- package/dist/esm/review/react/HeldWritesNotice.d.ts.map +1 -0
- package/dist/esm/review/react/HeldWritesNotice.js +19 -0
- package/dist/esm/review/react/HeldWritesNotice.js.map +1 -0
- package/dist/esm/review/react/index.d.ts +5 -0
- package/dist/esm/review/react/index.d.ts.map +1 -0
- package/dist/esm/review/react/index.js +5 -0
- package/dist/esm/review/react/index.js.map +1 -0
- package/dist/esm/review/react/useHeldWrite.d.ts +63 -0
- package/dist/esm/review/react/useHeldWrite.d.ts.map +1 -0
- package/dist/esm/review/react/useHeldWrite.js +104 -0
- package/dist/esm/review/react/useHeldWrite.js.map +1 -0
- package/dist/esm/review/react/useHeldWrites.d.ts +40 -0
- package/dist/esm/review/react/useHeldWrites.d.ts.map +1 -0
- package/dist/esm/review/react/useHeldWrites.js +91 -0
- package/dist/esm/review/react/useHeldWrites.js.map +1 -0
- package/dist/esm/review/react/useSavedAttempt.d.ts +54 -0
- package/dist/esm/review/react/useSavedAttempt.d.ts.map +1 -0
- package/dist/esm/review/react/useSavedAttempt.js +102 -0
- package/dist/esm/review/react/useSavedAttempt.js.map +1 -0
- package/dist/esm/review/savedAttempt.d.ts +180 -0
- package/dist/esm/review/savedAttempt.d.ts.map +1 -0
- package/dist/esm/review/savedAttempt.js +524 -0
- package/dist/esm/review/savedAttempt.js.map +1 -0
- package/dist/esm/review/writeHold.d.ts +94 -2
- package/dist/esm/review/writeHold.d.ts.map +1 -1
- package/dist/esm/review/writeHold.js +285 -44
- package/dist/esm/review/writeHold.js.map +1 -1
- package/dist/esm/review/writeRecovery.d.ts +58 -0
- package/dist/esm/review/writeRecovery.d.ts.map +1 -1
- package/dist/esm/review/writeRecovery.js +160 -2
- package/dist/esm/review/writeRecovery.js.map +1 -1
- package/package.json +16 -2
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import { type Address, type Hex, type PublicClient, type TransactionReceipt } from "viem";
|
|
2
2
|
import { type SafeQueuedTransaction, type SafeServiceOptions } from "../safeService.js";
|
|
3
3
|
import { type HeldWriteStorage, type ReviewedWriteRecoveryInput, type ReviewedWriteRecoveryRecord } from "./writeRecovery.js";
|
|
4
|
+
/** A saved success the user hasn't acknowledged: it blocks sending the action again. */
|
|
5
|
+
export type UnacknowledgedSuccess = {
|
|
6
|
+
result: "success";
|
|
7
|
+
hash: Hex;
|
|
8
|
+
/** The reservation it settled. */
|
|
9
|
+
reservation?: string;
|
|
10
|
+
};
|
|
4
11
|
/** The reads a write hold makes on the call's chain; a viem PublicClient satisfies it. */
|
|
5
12
|
export type WriteHoldClient = Pick<PublicClient, "getBlock" | "getBlockNumber" | "getChainId" | "getTransaction" | "getTransactionCount" | "getTransactionReceipt" | "request">;
|
|
6
13
|
/** How a held write ended, when the hold saw it end. */
|
|
7
14
|
export type WriteHoldSettled =
|
|
8
|
-
/** Its verified receipt (a revert only once final). */
|
|
15
|
+
/** Its verified receipt (a revert only once final); `acknowledged` once the user saw it. */
|
|
9
16
|
{
|
|
10
17
|
result: "success" | "failed";
|
|
11
18
|
hash: Hex;
|
|
19
|
+
acknowledged?: true;
|
|
12
20
|
}
|
|
13
21
|
/** A Safe proposal's expiry before it ran is proven. */
|
|
14
22
|
| {
|
|
@@ -230,13 +238,97 @@ export declare function createWriteHold(options?: {
|
|
|
230
238
|
safe?: {
|
|
231
239
|
safeTxHash: Hex;
|
|
232
240
|
};
|
|
233
|
-
} | undefined, client?: WriteHoldClient | undefined) => Promise<WriteHoldState
|
|
241
|
+
} | undefined, client?: WriteHoldClient | undefined) => Promise<WriteHoldState | (WriteHoldState & {
|
|
242
|
+
declined?: "refused" | "unreadable";
|
|
243
|
+
})>;
|
|
234
244
|
/**
|
|
235
245
|
* Every state this controller reads or makes for the call, and other
|
|
236
246
|
* tabs' changes. The latest one, if any, is replayed at once.
|
|
237
247
|
*/
|
|
238
248
|
subscribe(listener: (state: WriteHoldState) => void): () => void;
|
|
249
|
+
/**
|
|
250
|
+
* The send gate's evidence for this key: its saved success, while no
|
|
251
|
+
* record is held and the user hasn't acknowledged it. Pure, from storage.
|
|
252
|
+
*/
|
|
253
|
+
unacknowledgedSuccess(skip?: (hash: Hex) => boolean): UnacknowledgedSuccess | undefined;
|
|
254
|
+
/** How `reservation` settled, if it is this key's latest and settled. */
|
|
255
|
+
settlementOf(reservation: string): WriteHoldSettled | undefined;
|
|
256
|
+
/**
|
|
257
|
+
* The user acknowledged a success the hold settled while they were
|
|
258
|
+
* away (or a view saw it settle): its saved settlement is marked
|
|
259
|
+
* acknowledged, keeping its result for every reader, so it blocks no
|
|
260
|
+
* send. Under the call's lock; nothing is sent.
|
|
261
|
+
*/
|
|
262
|
+
acknowledge(settled: {
|
|
263
|
+
result: "success" | "failed";
|
|
264
|
+
hash: Hex;
|
|
265
|
+
}): Promise<WriteHoldState>;
|
|
239
266
|
};
|
|
267
|
+
list: ({ account, chainId }: {
|
|
268
|
+
account: Address;
|
|
269
|
+
chainId: number;
|
|
270
|
+
}) => {
|
|
271
|
+
key: string;
|
|
272
|
+
record: ReviewedWriteRecoveryRecord;
|
|
273
|
+
handle: {
|
|
274
|
+
peek: () => WriteHoldState;
|
|
275
|
+
state(client: WriteHoldClient, checks?: {
|
|
276
|
+
effect?: (chainId: number) => Promise<boolean>;
|
|
277
|
+
}): Promise<WriteHoldState>;
|
|
278
|
+
send<T>(client: WriteHoldClient, run: (gate: WriteHoldGate) => Promise<T>): Promise<T>;
|
|
279
|
+
exit(snapshot: WriteHoldState, acknowledgement: {
|
|
280
|
+
checkedWallet: true;
|
|
281
|
+
}, client: WriteHoldClient): Promise<{
|
|
282
|
+
released: boolean;
|
|
283
|
+
state: WriteHoldState;
|
|
284
|
+
}>;
|
|
285
|
+
onReceipt: (receipt: TransactionReceipt, client: WriteHoldClient, proof?: {
|
|
286
|
+
calls: readonly ReviewedWriteRecoveryInput["call"][];
|
|
287
|
+
batch?: boolean;
|
|
288
|
+
} | undefined) => Promise<WriteHoldState>;
|
|
289
|
+
onUnproven: (client: WriteHoldClient, proposalHash?: `0x${string}` | undefined) => Promise<WriteHoldState>;
|
|
290
|
+
onExecuted: (client: WriteHoldClient, executionHash?: `0x${string}` | undefined) => Promise<WriteHoldState>;
|
|
291
|
+
attachHash: (client: WriteHoldClient, hash: `0x${string}`) => Promise<WriteHoldState>;
|
|
292
|
+
attachSafeNonce: (client: WriteHoldClient, args_1: {
|
|
293
|
+
safeTxHash: Hex;
|
|
294
|
+
nonce: number;
|
|
295
|
+
}) => Promise<WriteHoldState>;
|
|
296
|
+
adopt: (snapshot: WriteHoldState, evidence?: {
|
|
297
|
+
nonce?: number | bigint;
|
|
298
|
+
sentNonce?: number | bigint;
|
|
299
|
+
fromBlock?: bigint;
|
|
300
|
+
submittedAt?: number;
|
|
301
|
+
hash?: Hex;
|
|
302
|
+
safe?: {
|
|
303
|
+
safeTxHash: Hex;
|
|
304
|
+
};
|
|
305
|
+
} | undefined, client?: WriteHoldClient | undefined) => Promise<WriteHoldState | (WriteHoldState & {
|
|
306
|
+
declined?: "refused" | "unreadable";
|
|
307
|
+
})>;
|
|
308
|
+
/**
|
|
309
|
+
* Every state this controller reads or makes for the call, and other
|
|
310
|
+
* tabs' changes. The latest one, if any, is replayed at once.
|
|
311
|
+
*/
|
|
312
|
+
subscribe(listener: (state: WriteHoldState) => void): () => void;
|
|
313
|
+
/**
|
|
314
|
+
* The send gate's evidence for this key: its saved success, while no
|
|
315
|
+
* record is held and the user hasn't acknowledged it. Pure, from storage.
|
|
316
|
+
*/
|
|
317
|
+
unacknowledgedSuccess(skip?: (hash: Hex) => boolean): UnacknowledgedSuccess | undefined;
|
|
318
|
+
/** How `reservation` settled, if it is this key's latest and settled. */
|
|
319
|
+
settlementOf(reservation: string): WriteHoldSettled | undefined;
|
|
320
|
+
/**
|
|
321
|
+
* The user acknowledged a success the hold settled while they were
|
|
322
|
+
* away (or a view saw it settle): its saved settlement is marked
|
|
323
|
+
* acknowledged, keeping its result for every reader, so it blocks no
|
|
324
|
+
* send. Under the call's lock; nothing is sent.
|
|
325
|
+
*/
|
|
326
|
+
acknowledge(settled: {
|
|
327
|
+
result: "success" | "failed";
|
|
328
|
+
hash: Hex;
|
|
329
|
+
}): Promise<WriteHoldState>;
|
|
330
|
+
};
|
|
331
|
+
}[];
|
|
240
332
|
/** Whether holds outlive this tab right now. */
|
|
241
333
|
durable: () => boolean;
|
|
242
334
|
/** The review's line while holds last only in this tab, or null. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"writeHold.d.ts","sourceRoot":"","sources":["../../../src/review/writeHold.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,OAAO,EACZ,KAAK,GAAG,EACR,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACxB,MAAM,MAAM,CAAC;AACd,OAAO,EAOL,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACxB,MAAM,mBAAmB,CAAC;AAgB3B,OAAO,
|
|
1
|
+
{"version":3,"file":"writeHold.d.ts","sourceRoot":"","sources":["../../../src/review/writeHold.ts"],"names":[],"mappings":"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"}
|
|
@@ -82,8 +82,10 @@ const UNSEEN_HASH_MS = 30 * 60_000;
|
|
|
82
82
|
/** The longest one request to Safe's service may take inside the hold. */
|
|
83
83
|
const SAFE_SERVICE_READ_MS = 8_000;
|
|
84
84
|
/** The 30 minutes have passed since the wallet returned the hash, or since it was first read. A clock that couldn't be saved (NaN) never runs out. */
|
|
85
|
-
function unseenTooLong(record
|
|
86
|
-
|
|
85
|
+
function unseenTooLong(record,
|
|
86
|
+
/** A later authenticated sighting, when there is one: the clock runs from it. */
|
|
87
|
+
seen) {
|
|
88
|
+
return (Date.now() - Number(seen ?? record.submittedAt ?? record.firstSeenAt) >=
|
|
87
89
|
UNSEEN_HASH_MS);
|
|
88
90
|
}
|
|
89
91
|
/** Whether a canonical finalized block shows the account's nonce still at or below the sent nonce; false when it can't say. */
|
|
@@ -388,10 +390,14 @@ function createWriteHold(options = {}) {
|
|
|
388
390
|
* exactly this call. One that can't be read is unknown, not refused.
|
|
389
391
|
*/
|
|
390
392
|
async function adoptable(hash, client) {
|
|
391
|
-
if (!(0, untrusted_js_1.isBytes32)(hash)
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
return
|
|
393
|
+
if (!(0, untrusted_js_1.isBytes32)(hash))
|
|
394
|
+
return "refused";
|
|
395
|
+
if (!client)
|
|
396
|
+
return "unreadable";
|
|
397
|
+
const chainId = await client.getChainId().catch(() => null);
|
|
398
|
+
// A client on another chain can't check this chain's transaction.
|
|
399
|
+
if (chainId !== call.chainId)
|
|
400
|
+
return "unreadable";
|
|
395
401
|
const reviewed = {
|
|
396
402
|
account: call.account.toLowerCase(),
|
|
397
403
|
chainId: call.chainId,
|
|
@@ -401,22 +407,35 @@ function createWriteHold(options = {}) {
|
|
|
401
407
|
value: String(call.call.value ?? 0),
|
|
402
408
|
},
|
|
403
409
|
};
|
|
410
|
+
// One the chain or the service can't show is this call's, held.
|
|
404
411
|
if (call.safe) {
|
|
405
412
|
const proposal = await (0, safeService_js_1.readSafeTransaction)(call.chainId, call.account, hash, service).catch(() => null);
|
|
406
|
-
return !proposal || (0, writeRecovery_js_1.safeProposalIsHeldCall)(proposal, call)
|
|
413
|
+
return !proposal || (0, writeRecovery_js_1.safeProposalIsHeldCall)(proposal, call)
|
|
414
|
+
? "yes"
|
|
415
|
+
: "refused";
|
|
407
416
|
}
|
|
408
417
|
const sent = await client.getTransaction({ hash }).catch(() => null);
|
|
409
|
-
return !sent || sentIsCall(sent, hash, reviewed);
|
|
418
|
+
return !sent || sentIsCall(sent, hash, reviewed) ? "yes" : "refused";
|
|
410
419
|
}
|
|
411
|
-
/**
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
+
/**
|
|
421
|
+
* Safe's authenticated record of the held proposal, or null while the
|
|
422
|
+
* service can't return it (down, or it has none).
|
|
423
|
+
*/
|
|
424
|
+
async function proposalOf(record) {
|
|
425
|
+
return (0, safeService_js_1.readSafeTransaction)(record.chainId, record.account, record.hash, service).catch(() => null);
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* A Safe write unseen too long: not proven run, not ended unproven (that
|
|
429
|
+
* has its own exit), and not listed unexecuted by the service for 30
|
|
430
|
+
* minutes since it was sent, adopted, or last listed.
|
|
431
|
+
*/
|
|
432
|
+
function unboundedSafe(record) {
|
|
433
|
+
return (record.safe &&
|
|
434
|
+
!!record.hash &&
|
|
435
|
+
!record.executed &&
|
|
436
|
+
!record.unproven &&
|
|
437
|
+
!record.replaced &&
|
|
438
|
+
unseenTooLong(record, record.pendingSeenAt));
|
|
420
439
|
}
|
|
421
440
|
/** Follow a saved execution's receipt; null while the node has none. */
|
|
422
441
|
async function execution(record, client) {
|
|
@@ -615,13 +634,18 @@ function createWriteHold(options = {}) {
|
|
|
615
634
|
return settled ?? ranExecuted(record);
|
|
616
635
|
}
|
|
617
636
|
}
|
|
618
|
-
// The chain's proof, from the proposal's nonce
|
|
619
|
-
//
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
637
|
+
// The chain's proof, from the proposal's nonce, saved once. Only the
|
|
638
|
+
// service returning this proposal unexecuted shows it truly pending:
|
|
639
|
+
// that read restarts its unseen clock. A Safe nonce still waiting shows
|
|
640
|
+
// only that nothing ran there.
|
|
641
|
+
const proposal = await proposalOf(record);
|
|
642
|
+
const listed = !!proposal && proposal.isExecuted !== true;
|
|
643
|
+
if (proposal && record.safeNonce === undefined)
|
|
644
|
+
record = recovery.proposalNonce(record, (0, safeService_js_1.safeTransactionMessage)(proposal).nonce);
|
|
645
|
+
// Listed: truly pending, an unproven end included. The fresh record
|
|
646
|
+
// carries the new stamp, so the checked answer below removes any exit.
|
|
647
|
+
if (listed)
|
|
648
|
+
record = recovery.listedAgain(record);
|
|
625
649
|
const end = (record.safeNonce !== undefined &&
|
|
626
650
|
(await (0, safeService_js_1.provenSafeProposalEnd)(client, record.account, hash, BigInt(record.safeNonce)))) ||
|
|
627
651
|
(await (0, safeService_js_1.lookAtSafeProposalEnd)(client, record.chainId, record.account, hash, service));
|
|
@@ -657,10 +681,9 @@ function createWriteHold(options = {}) {
|
|
|
657
681
|
return clear(settled, record.id);
|
|
658
682
|
}
|
|
659
683
|
}
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
unseenTooLong(record))
|
|
684
|
+
// Its wait is bounded like any unchecked write, the clock restarted by
|
|
685
|
+
// each listing (an unproven end has its own exit).
|
|
686
|
+
if (unboundedSafe(record))
|
|
664
687
|
return unchecked(record);
|
|
665
688
|
if (record.executed)
|
|
666
689
|
follow(client, record.id);
|
|
@@ -698,9 +721,13 @@ function createWriteHold(options = {}) {
|
|
|
698
721
|
// A mirror carries no evidence of its own: its source attempt does.
|
|
699
722
|
if (record.mirrorOf)
|
|
700
723
|
return classify(record);
|
|
701
|
-
// No evidence from another chain.
|
|
702
|
-
|
|
703
|
-
|
|
724
|
+
// No evidence from another chain. Unreadable chain identity still
|
|
725
|
+
// bounds a Safe write's unchecked wait.
|
|
726
|
+
const chainId = await client.getChainId().catch(() => null);
|
|
727
|
+
if (chainId !== record.chainId)
|
|
728
|
+
return chainId === null && unboundedSafe(record)
|
|
729
|
+
? unchecked(record)
|
|
730
|
+
: classify(record);
|
|
704
731
|
if (record.safe)
|
|
705
732
|
return safeState(record, client);
|
|
706
733
|
const check = await recovery
|
|
@@ -1045,10 +1072,13 @@ function createWriteHold(options = {}) {
|
|
|
1045
1072
|
if (hooks.across) {
|
|
1046
1073
|
// Under an intent: the same atomic reserve as a send, under every
|
|
1047
1074
|
// legacy key's lock, mirrored at each so older versions see it.
|
|
1048
|
-
if (!free()
|
|
1049
|
-
(hash !== undefined && !(await adoptable(hash, client))))
|
|
1075
|
+
if (!free())
|
|
1050
1076
|
return shown(peek());
|
|
1077
|
+
const verdict = hash === undefined ? "yes" : await adoptable(hash, client);
|
|
1078
|
+
if (verdict !== "yes")
|
|
1079
|
+
return { ...shown(peek()), declined: verdict };
|
|
1051
1080
|
let adopted = false;
|
|
1081
|
+
let busy = false;
|
|
1052
1082
|
try {
|
|
1053
1083
|
const { released } = await hooks.across((work) => recovery.withLock(work), () => {
|
|
1054
1084
|
if (!free())
|
|
@@ -1058,21 +1088,34 @@ function createWriteHold(options = {}) {
|
|
|
1058
1088
|
}, recovery.rejected, Promise.resolve(), hooks.generations());
|
|
1059
1089
|
await released;
|
|
1060
1090
|
}
|
|
1061
|
-
catch {
|
|
1062
|
-
|
|
1091
|
+
catch (error) {
|
|
1092
|
+
// Held elsewhere or no longer free: what the hold shows. Busy: unread.
|
|
1093
|
+
busy = error instanceof WriteHoldBusyError;
|
|
1063
1094
|
}
|
|
1064
1095
|
// A mined hash settles on its verified receipt, through the gate.
|
|
1065
|
-
|
|
1096
|
+
if (adopted && hash && client)
|
|
1097
|
+
return state(client);
|
|
1098
|
+
const now = shown(peek());
|
|
1099
|
+
return busy && now.status === "clear"
|
|
1100
|
+
? { ...now, declined: "unreadable" }
|
|
1101
|
+
: now;
|
|
1066
1102
|
}
|
|
1067
1103
|
const result = await locked(async () => {
|
|
1068
1104
|
if (!free())
|
|
1069
1105
|
return peek();
|
|
1070
|
-
|
|
1071
|
-
|
|
1106
|
+
const verdict = hash === undefined ? "yes" : await adoptable(hash, client);
|
|
1107
|
+
if (verdict !== "yes")
|
|
1108
|
+
return { ...peek(), declined: verdict };
|
|
1072
1109
|
reserve();
|
|
1073
1110
|
return hash && client ? inspect(client) : peek();
|
|
1074
1111
|
}, true);
|
|
1075
|
-
|
|
1112
|
+
if (!result)
|
|
1113
|
+
return { ...shown(peek()), declined: "unreadable" };
|
|
1114
|
+
const { declined, ...answer } = result.value;
|
|
1115
|
+
return {
|
|
1116
|
+
...shown(answer),
|
|
1117
|
+
...(declined ? { declined } : {}),
|
|
1118
|
+
};
|
|
1076
1119
|
},
|
|
1077
1120
|
/**
|
|
1078
1121
|
* Save the Safe nonce of a held Safe proposal adopted before it was
|
|
@@ -1099,6 +1142,46 @@ function createWriteHold(options = {}) {
|
|
|
1099
1142
|
}, true);
|
|
1100
1143
|
return shown(result?.value ?? peek());
|
|
1101
1144
|
},
|
|
1145
|
+
/**
|
|
1146
|
+
* The send gate's evidence for this key: its saved success, while no
|
|
1147
|
+
* record is held and the user hasn't acknowledged it. Pure, from storage.
|
|
1148
|
+
*/
|
|
1149
|
+
unacknowledgedSuccess(
|
|
1150
|
+
/** A success to look past (one a view already told, its acknowledgement under way). */
|
|
1151
|
+
skip) {
|
|
1152
|
+
if (recovery.read())
|
|
1153
|
+
return undefined;
|
|
1154
|
+
const settled = recovery.settled();
|
|
1155
|
+
return settled?.result === "success" &&
|
|
1156
|
+
!settled.acknowledged &&
|
|
1157
|
+
!skip?.(settled.hash)
|
|
1158
|
+
? {
|
|
1159
|
+
result: "success",
|
|
1160
|
+
hash: settled.hash,
|
|
1161
|
+
reservation: recovery.latestReservation(),
|
|
1162
|
+
}
|
|
1163
|
+
: undefined;
|
|
1164
|
+
},
|
|
1165
|
+
/** How `reservation` settled, if it is this key's latest and settled. */
|
|
1166
|
+
settlementOf(reservation) {
|
|
1167
|
+
const now = peek();
|
|
1168
|
+
return now.status === "clear" && now.reservation === reservation
|
|
1169
|
+
? now.settled
|
|
1170
|
+
: undefined;
|
|
1171
|
+
},
|
|
1172
|
+
/**
|
|
1173
|
+
* The user acknowledged a success the hold settled while they were
|
|
1174
|
+
* away (or a view saw it settle): its saved settlement is marked
|
|
1175
|
+
* acknowledged, keeping its result for every reader, so it blocks no
|
|
1176
|
+
* send. Under the call's lock; nothing is sent.
|
|
1177
|
+
*/
|
|
1178
|
+
async acknowledge(settled) {
|
|
1179
|
+
const result = await locked(async () => {
|
|
1180
|
+
recovery.acknowledgeSettled(settled);
|
|
1181
|
+
return peek();
|
|
1182
|
+
}, true);
|
|
1183
|
+
return shown(result?.value ?? peek());
|
|
1184
|
+
},
|
|
1102
1185
|
async attachHash(client, hash) {
|
|
1103
1186
|
const result = await locked(async () => {
|
|
1104
1187
|
const record = recovery.read();
|
|
@@ -1261,10 +1344,20 @@ function createWriteHold(options = {}) {
|
|
|
1261
1344
|
? [{ input: { ...exact, call: source.call } }]
|
|
1262
1345
|
: []));
|
|
1263
1346
|
rescan();
|
|
1347
|
+
/** The legacy hold this intent last stood for, with its reservation. */
|
|
1348
|
+
let routed;
|
|
1264
1349
|
/** A legacy key holding anything but this intent's own mirror. */
|
|
1265
1350
|
const foreign = (index) => holds(journals[index]) && delegates[index].peek().status !== "clear";
|
|
1266
1351
|
/** The legacy hold the intent stands for right now, from storage alone. */
|
|
1267
|
-
const active = () =>
|
|
1352
|
+
const active = () => {
|
|
1353
|
+
const index = delegates.findIndex((_, at) => foreign(at));
|
|
1354
|
+
if (index < 0)
|
|
1355
|
+
return undefined;
|
|
1356
|
+
const now = delegates[index].peek();
|
|
1357
|
+
if (now.status !== "clear")
|
|
1358
|
+
routed = { handle: delegates[index], reservation: now.record.id };
|
|
1359
|
+
return delegates[index];
|
|
1360
|
+
};
|
|
1268
1361
|
/** The first legacy key holding an unresolved write, through its own gate. */
|
|
1269
1362
|
async function delegated(client) {
|
|
1270
1363
|
rescan();
|
|
@@ -1272,11 +1365,83 @@ function createWriteHold(options = {}) {
|
|
|
1272
1365
|
if (!foreign(index))
|
|
1273
1366
|
continue;
|
|
1274
1367
|
const state = await handle.state(client);
|
|
1275
|
-
if (state.status !== "clear")
|
|
1368
|
+
if (state.status !== "clear") {
|
|
1369
|
+
routed = { handle, reservation: state.record.id };
|
|
1276
1370
|
return state;
|
|
1371
|
+
}
|
|
1277
1372
|
}
|
|
1278
1373
|
return null;
|
|
1279
1374
|
}
|
|
1375
|
+
/**
|
|
1376
|
+
* How a legacy hold this intent stood for ended, while the intent itself
|
|
1377
|
+
* never reserved: its settlement (acknowledged or not) is the intent's,
|
|
1378
|
+
* so a view that saw it held shows its result, and an unacknowledged
|
|
1379
|
+
* success still blocks a fresh one.
|
|
1380
|
+
*/
|
|
1381
|
+
/**
|
|
1382
|
+
* Every legacy settlement that may be the intent's: the reservation it
|
|
1383
|
+
* was seen standing for (first), and any reserved after (or not provably
|
|
1384
|
+
* before) its own latest reservation. Times that can't be compared count
|
|
1385
|
+
* as newer: a false block is the safe side.
|
|
1386
|
+
*/
|
|
1387
|
+
function eligibleLegacy() {
|
|
1388
|
+
const eligible = [];
|
|
1389
|
+
if (routed) {
|
|
1390
|
+
const now = routed.handle.peek();
|
|
1391
|
+
if (now.status === "clear" &&
|
|
1392
|
+
now.settled &&
|
|
1393
|
+
now.reservation === routed.reservation)
|
|
1394
|
+
eligible.push({ handle: routed.handle, state: now });
|
|
1395
|
+
}
|
|
1396
|
+
const ownReserved = ownJournal.latestReservation() !== undefined;
|
|
1397
|
+
const ownAt = ownJournal.latestReservedAt();
|
|
1398
|
+
for (const [index, handle] of delegates.entries()) {
|
|
1399
|
+
if (eligible.some((entry) => entry.handle === handle))
|
|
1400
|
+
continue;
|
|
1401
|
+
const now = handle.peek();
|
|
1402
|
+
if (now.status !== "clear" || !now.settled)
|
|
1403
|
+
continue;
|
|
1404
|
+
const legacyAt = journals[index].latestReservedAt() ?? journals[index].settledAt();
|
|
1405
|
+
if (!ownReserved ||
|
|
1406
|
+
ownAt === undefined ||
|
|
1407
|
+
legacyAt === undefined ||
|
|
1408
|
+
// The same moment is no proof of order: counted as newer.
|
|
1409
|
+
legacyAt >= ownAt)
|
|
1410
|
+
eligible.push({ handle, state: now });
|
|
1411
|
+
}
|
|
1412
|
+
return eligible;
|
|
1413
|
+
}
|
|
1414
|
+
/**
|
|
1415
|
+
* What the intent shows of its legacy holds: the settlement of the one
|
|
1416
|
+
* it was seen standing for (so it is delivered), else an unacknowledged
|
|
1417
|
+
* success, else any eligible one. Blocking is the send gate's
|
|
1418
|
+
* (unacknowledgedSuccess), never this choice.
|
|
1419
|
+
*/
|
|
1420
|
+
function legacySettled() {
|
|
1421
|
+
const eligible = eligibleLegacy();
|
|
1422
|
+
return (eligible.find(({ handle, state }) => handle === routed?.handle &&
|
|
1423
|
+
state.reservation === routed.reservation) ??
|
|
1424
|
+
eligible.find(({ state }) => state.settled.result === "success" &&
|
|
1425
|
+
!("acknowledged" in state.settled && state.settled.acknowledged)) ??
|
|
1426
|
+
eligible[0]);
|
|
1427
|
+
}
|
|
1428
|
+
/**
|
|
1429
|
+
* `state`, or, when it is a clear, the legacy settlement that owns the
|
|
1430
|
+
* intent's result instead: the one it was seen standing for, or one
|
|
1431
|
+
* reserved after its own latest reservation, whatever the intent's own
|
|
1432
|
+
* (older) settlement says. One choice for reads, events and the guard.
|
|
1433
|
+
*/
|
|
1434
|
+
function withLegacy(state) {
|
|
1435
|
+
if (state.status !== "clear")
|
|
1436
|
+
return state;
|
|
1437
|
+
const legacy = legacySettled();
|
|
1438
|
+
return legacy
|
|
1439
|
+
? {
|
|
1440
|
+
...legacy.state,
|
|
1441
|
+
...(state.checked === undefined ? {} : { checked: state.checked }),
|
|
1442
|
+
}
|
|
1443
|
+
: state;
|
|
1444
|
+
}
|
|
1280
1445
|
/**
|
|
1281
1446
|
* The final check and reservation, under every legacy key's lock taken
|
|
1282
1447
|
* in one sorted order (the intent's own is held by its send), each
|
|
@@ -1403,9 +1568,64 @@ function createWriteHold(options = {}) {
|
|
|
1403
1568
|
};
|
|
1404
1569
|
return {
|
|
1405
1570
|
...own,
|
|
1406
|
-
peek: () => active()?.peek() ?? own.peek(),
|
|
1571
|
+
peek: () => active()?.peek() ?? withLegacy(own.peek()),
|
|
1572
|
+
/**
|
|
1573
|
+
* The intent's events, through the same owner as its state(): while a
|
|
1574
|
+
* legacy hold stands for it, its own empty clear is that hold's state
|
|
1575
|
+
* (or its settlement), never a release.
|
|
1576
|
+
*/
|
|
1577
|
+
subscribe: (listener) => own.subscribe((state) => listener(state.status === "clear"
|
|
1578
|
+
? (active()?.peek() ?? withLegacy(state))
|
|
1579
|
+
: state)),
|
|
1407
1580
|
async state(client, checks) {
|
|
1408
|
-
return ((await delegated(client)) ??
|
|
1581
|
+
return ((await delegated(client)) ??
|
|
1582
|
+
withLegacy(await after(await own.state(client, checks))));
|
|
1583
|
+
},
|
|
1584
|
+
/**
|
|
1585
|
+
* The send gate: any unacknowledged success, the intent's own or an
|
|
1586
|
+
* eligible legacy hold's. Pure, from storage, whatever a view shows.
|
|
1587
|
+
*/
|
|
1588
|
+
unacknowledgedSuccess(skip) {
|
|
1589
|
+
// Every eligible success is considered: one looked past never hides
|
|
1590
|
+
// another.
|
|
1591
|
+
const mine = own.unacknowledgedSuccess(skip);
|
|
1592
|
+
if (mine)
|
|
1593
|
+
return mine;
|
|
1594
|
+
for (const { state } of eligibleLegacy()) {
|
|
1595
|
+
const settled = state.settled;
|
|
1596
|
+
if (settled.result === "success" &&
|
|
1597
|
+
"hash" in settled &&
|
|
1598
|
+
!settled.acknowledged &&
|
|
1599
|
+
!skip?.(settled.hash))
|
|
1600
|
+
return {
|
|
1601
|
+
result: "success",
|
|
1602
|
+
hash: settled.hash,
|
|
1603
|
+
reservation: state.reservation,
|
|
1604
|
+
};
|
|
1605
|
+
}
|
|
1606
|
+
return undefined;
|
|
1607
|
+
},
|
|
1608
|
+
/**
|
|
1609
|
+
* How a reservation this intent stood for settled, on its own key or a
|
|
1610
|
+
* legacy one, whichever hold is shown now.
|
|
1611
|
+
*/
|
|
1612
|
+
settlementOf(reservation) {
|
|
1613
|
+
for (const handle of [own, ...delegates]) {
|
|
1614
|
+
const settled = handle.settlementOf(reservation);
|
|
1615
|
+
if (settled)
|
|
1616
|
+
return settled;
|
|
1617
|
+
}
|
|
1618
|
+
return undefined;
|
|
1619
|
+
},
|
|
1620
|
+
/** A settlement is acknowledged where it was saved, found by its hash. */
|
|
1621
|
+
async acknowledge(settled) {
|
|
1622
|
+
const hash = settled.hash.toLowerCase();
|
|
1623
|
+
const legacy = eligibleLegacy().find(({ state }) => state.settled !== undefined &&
|
|
1624
|
+
"hash" in state.settled &&
|
|
1625
|
+
state.settled.hash === hash);
|
|
1626
|
+
return legacy
|
|
1627
|
+
? withLegacy(await legacy.handle.acknowledge(settled))
|
|
1628
|
+
: own.acknowledge(settled);
|
|
1409
1629
|
},
|
|
1410
1630
|
async send(client, run) {
|
|
1411
1631
|
const held = await delegated(client);
|
|
@@ -1521,8 +1741,29 @@ function createWriteHold(options = {}) {
|
|
|
1521
1741
|
adopt: async (...args) => route()?.peek() ?? own.adopt(...args),
|
|
1522
1742
|
};
|
|
1523
1743
|
}
|
|
1744
|
+
/**
|
|
1745
|
+
* Every write held for `account` on `chainId`, with a handle to each at
|
|
1746
|
+
* the key it was saved under: for an app-wide notice of everything held,
|
|
1747
|
+
* whatever action made it. Read from storage alone; each handle's state()
|
|
1748
|
+
* is the gated answer.
|
|
1749
|
+
*/
|
|
1750
|
+
function list({ account, chainId }) {
|
|
1751
|
+
return (0, writeRecovery_js_1.listReviewedWrites)({ account, chainId }, { storage }).map(({ key, record }) => {
|
|
1752
|
+
const input = {
|
|
1753
|
+
chainId: record.chainId,
|
|
1754
|
+
account: record.account,
|
|
1755
|
+
safe: record.safe,
|
|
1756
|
+
call: record.call,
|
|
1757
|
+
};
|
|
1758
|
+
const handle = record.namespace === undefined
|
|
1759
|
+
? openExact(input, key)
|
|
1760
|
+
: open({ ...input, namespace: record.namespace });
|
|
1761
|
+
return { key, record, handle };
|
|
1762
|
+
});
|
|
1763
|
+
}
|
|
1524
1764
|
return {
|
|
1525
1765
|
open,
|
|
1766
|
+
list,
|
|
1526
1767
|
/** Whether holds outlive this tab right now. */
|
|
1527
1768
|
durable: () => storage.durable(),
|
|
1528
1769
|
/** The review's line while holds last only in this tab, or null. */
|