@bananapus/nana-sdk-core 3.5.2 → 4.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 +489 -0
- package/dist/cjs/actions/suckerPairs.d.ts +5 -3
- package/dist/cjs/actions/suckerPairs.d.ts.map +1 -1
- package/dist/cjs/actions/suckerPairs.js +6 -26
- package/dist/cjs/actions/suckerPairs.js.map +1 -1
- package/dist/cjs/pause.d.ts +2 -0
- package/dist/cjs/pause.d.ts.map +1 -1
- package/dist/cjs/pause.js +17 -0
- package/dist/cjs/pause.js.map +1 -1
- package/dist/cjs/review/confirm.d.ts +52 -0
- package/dist/cjs/review/confirm.d.ts.map +1 -0
- package/dist/cjs/review/confirm.js +88 -0
- package/dist/cjs/review/confirm.js.map +1 -0
- package/dist/cjs/review/contractWrite.d.ts +5 -3
- package/dist/cjs/review/contractWrite.d.ts.map +1 -1
- package/dist/cjs/review/contractWrite.js +8 -7
- package/dist/cjs/review/contractWrite.js.map +1 -1
- package/dist/cjs/review/decode.d.ts +19 -1
- package/dist/cjs/review/decode.d.ts.map +1 -1
- package/dist/cjs/review/decode.js +30 -11
- package/dist/cjs/review/decode.js.map +1 -1
- package/dist/cjs/review/decodeCall.d.ts +21 -0
- package/dist/cjs/review/decodeCall.d.ts.map +1 -0
- package/dist/cjs/review/decodeCall.js +183 -0
- package/dist/cjs/review/decodeCall.js.map +1 -0
- package/dist/cjs/review/heldWrite.d.ts.map +1 -1
- package/dist/cjs/review/heldWrite.js +5 -4
- package/dist/cjs/review/heldWrite.js.map +1 -1
- package/dist/cjs/review/index.d.ts +11 -0
- package/dist/cjs/review/index.d.ts.map +1 -1
- package/dist/cjs/review/index.js +24 -0
- package/dist/cjs/review/index.js.map +1 -1
- package/dist/cjs/review/intents.d.ts +10 -0
- package/dist/cjs/review/intents.d.ts.map +1 -1
- package/dist/cjs/review/intents.js +13 -0
- package/dist/cjs/review/intents.js.map +1 -1
- package/dist/cjs/review/lineError.d.ts +34 -0
- package/dist/cjs/review/lineError.d.ts.map +1 -0
- package/dist/cjs/review/lineError.js +42 -0
- package/dist/cjs/review/lineError.js.map +1 -0
- package/dist/cjs/review/messages.d.ts +15 -3
- package/dist/cjs/review/messages.d.ts.map +1 -1
- package/dist/cjs/review/messages.js +16 -4
- package/dist/cjs/review/messages.js.map +1 -1
- package/dist/cjs/review/model.d.ts +149 -0
- package/dist/cjs/review/model.d.ts.map +1 -0
- package/dist/cjs/review/model.js +750 -0
- package/dist/cjs/review/model.js.map +1 -0
- package/dist/cjs/review/plan.d.ts +63 -0
- package/dist/cjs/review/plan.d.ts.map +1 -0
- package/dist/cjs/review/plan.js +149 -0
- package/dist/cjs/review/plan.js.map +1 -0
- package/dist/cjs/review/react/index.d.ts +1 -0
- package/dist/cjs/review/react/index.d.ts.map +1 -1
- package/dist/cjs/review/react/index.js +1 -0
- package/dist/cjs/review/react/index.js.map +1 -1
- package/dist/cjs/review/react/useReviewedRun.d.ts +96 -0
- package/dist/cjs/review/react/useReviewedRun.d.ts.map +1 -0
- package/dist/cjs/review/react/useReviewedRun.js +261 -0
- package/dist/cjs/review/react/useReviewedRun.js.map +1 -0
- package/dist/cjs/review/receipt.d.ts +4 -1
- package/dist/cjs/review/receipt.d.ts.map +1 -1
- package/dist/cjs/review/receipt.js +7 -3
- package/dist/cjs/review/receipt.js.map +1 -1
- package/dist/cjs/review/relayr.d.ts +13 -4
- package/dist/cjs/review/relayr.d.ts.map +1 -1
- package/dist/cjs/review/relayr.js +51 -8
- package/dist/cjs/review/relayr.js.map +1 -1
- package/dist/cjs/review/relayrSend.d.ts +135 -0
- package/dist/cjs/review/relayrSend.d.ts.map +1 -0
- package/dist/cjs/review/relayrSend.js +943 -0
- package/dist/cjs/review/relayrSend.js.map +1 -0
- package/dist/cjs/review/reviewQueue.d.ts +10 -9
- package/dist/cjs/review/reviewQueue.d.ts.map +1 -1
- package/dist/cjs/review/reviewQueue.js +19 -29
- package/dist/cjs/review/reviewQueue.js.map +1 -1
- package/dist/cjs/review/reviewRequests.d.ts +86 -0
- package/dist/cjs/review/reviewRequests.d.ts.map +1 -0
- package/dist/cjs/review/reviewRequests.js +266 -0
- package/dist/cjs/review/reviewRequests.js.map +1 -0
- package/dist/cjs/review/safeRelayr.d.ts +3 -1
- package/dist/cjs/review/safeRelayr.d.ts.map +1 -1
- package/dist/cjs/review/safeRelayr.js +5 -1
- package/dist/cjs/review/safeRelayr.js.map +1 -1
- package/dist/cjs/review/safeSend.d.ts +69 -0
- package/dist/cjs/review/safeSend.d.ts.map +1 -0
- package/dist/cjs/review/safeSend.js +308 -0
- package/dist/cjs/review/safeSend.js.map +1 -0
- package/dist/cjs/review/send.d.ts +241 -0
- package/dist/cjs/review/send.d.ts.map +1 -0
- package/dist/cjs/review/send.js +1017 -0
- package/dist/cjs/review/send.js.map +1 -0
- package/dist/cjs/review/sequence.d.ts +77 -0
- package/dist/cjs/review/sequence.d.ts.map +1 -0
- package/dist/cjs/review/sequence.js +232 -0
- package/dist/cjs/review/sequence.js.map +1 -0
- package/dist/cjs/review/sign.d.ts +109 -0
- package/dist/cjs/review/sign.d.ts.map +1 -0
- package/dist/cjs/review/sign.js +374 -0
- package/dist/cjs/review/sign.js.map +1 -0
- package/dist/cjs/review/simulation.d.ts +41 -2
- package/dist/cjs/review/simulation.d.ts.map +1 -1
- package/dist/cjs/review/simulation.js +99 -29
- package/dist/cjs/review/simulation.js.map +1 -1
- package/dist/cjs/review/transaction-message.d.ts +13 -0
- package/dist/cjs/review/transaction-message.d.ts.map +1 -1
- package/dist/cjs/review/transaction-message.js +25 -0
- package/dist/cjs/review/transaction-message.js.map +1 -1
- package/dist/cjs/review/transactionReview.d.ts +27 -19
- package/dist/cjs/review/transactionReview.d.ts.map +1 -1
- package/dist/cjs/review/transactionReview.js +22 -63
- package/dist/cjs/review/transactionReview.js.map +1 -1
- package/dist/cjs/review/wallet.d.ts +82 -0
- package/dist/cjs/review/wallet.d.ts.map +1 -0
- package/dist/cjs/review/wallet.js +157 -0
- package/dist/cjs/review/wallet.js.map +1 -0
- package/dist/cjs/review/writeHold.d.ts +100 -12
- package/dist/cjs/review/writeHold.d.ts.map +1 -1
- package/dist/cjs/review/writeHold.js +61 -13
- package/dist/cjs/review/writeHold.js.map +1 -1
- package/dist/cjs/review/writeRecovery.d.ts +6 -1
- package/dist/cjs/review/writeRecovery.d.ts.map +1 -1
- package/dist/cjs/review/writeRecovery.js +108 -40
- package/dist/cjs/review/writeRecovery.js.map +1 -1
- package/dist/cjs/safeService.d.ts +27 -4
- package/dist/cjs/safeService.d.ts.map +1 -1
- package/dist/cjs/safeService.js +120 -3
- package/dist/cjs/safeService.js.map +1 -1
- package/dist/cjs/testing.d.ts +24 -0
- package/dist/cjs/testing.d.ts.map +1 -1
- package/dist/cjs/testing.js +26 -1
- package/dist/cjs/testing.js.map +1 -1
- package/dist/cjs/v6/defifa.d.ts.map +1 -1
- package/dist/cjs/v6/defifa.js +24 -23
- package/dist/cjs/v6/defifa.js.map +1 -1
- package/dist/cjs/v6/executionErrors.d.ts.map +1 -1
- package/dist/cjs/v6/executionErrors.js +3 -2
- package/dist/cjs/v6/executionErrors.js.map +1 -1
- package/dist/cjs/v6/pay.d.ts +25 -8
- package/dist/cjs/v6/pay.d.ts.map +1 -1
- package/dist/cjs/v6/pay.js +117 -23
- package/dist/cjs/v6/pay.js.map +1 -1
- package/dist/cjs/v6/suckers.d.ts +30 -0
- package/dist/cjs/v6/suckers.d.ts.map +1 -1
- package/dist/cjs/v6/suckers.js +69 -5
- package/dist/cjs/v6/suckers.js.map +1 -1
- package/dist/esm/actions/suckerPairs.d.ts +5 -3
- package/dist/esm/actions/suckerPairs.d.ts.map +1 -1
- package/dist/esm/actions/suckerPairs.js +7 -27
- package/dist/esm/actions/suckerPairs.js.map +1 -1
- package/dist/esm/pause.d.ts +2 -0
- package/dist/esm/pause.d.ts.map +1 -1
- package/dist/esm/pause.js +16 -0
- package/dist/esm/pause.js.map +1 -1
- package/dist/esm/review/confirm.d.ts +52 -0
- package/dist/esm/review/confirm.d.ts.map +1 -0
- package/dist/esm/review/confirm.js +83 -0
- package/dist/esm/review/confirm.js.map +1 -0
- package/dist/esm/review/contractWrite.d.ts +5 -3
- package/dist/esm/review/contractWrite.d.ts.map +1 -1
- package/dist/esm/review/contractWrite.js +8 -7
- package/dist/esm/review/contractWrite.js.map +1 -1
- package/dist/esm/review/decode.d.ts +19 -1
- package/dist/esm/review/decode.d.ts.map +1 -1
- package/dist/esm/review/decode.js +29 -14
- package/dist/esm/review/decode.js.map +1 -1
- package/dist/esm/review/decodeCall.d.ts +21 -0
- package/dist/esm/review/decodeCall.d.ts.map +1 -0
- package/dist/esm/review/decodeCall.js +180 -0
- package/dist/esm/review/decodeCall.js.map +1 -0
- package/dist/esm/review/heldWrite.d.ts.map +1 -1
- package/dist/esm/review/heldWrite.js +5 -4
- package/dist/esm/review/heldWrite.js.map +1 -1
- package/dist/esm/review/index.d.ts +11 -0
- package/dist/esm/review/index.d.ts.map +1 -1
- package/dist/esm/review/index.js +11 -0
- package/dist/esm/review/index.js.map +1 -1
- package/dist/esm/review/intents.d.ts +10 -0
- package/dist/esm/review/intents.d.ts.map +1 -1
- package/dist/esm/review/intents.js +12 -0
- package/dist/esm/review/intents.js.map +1 -1
- package/dist/esm/review/lineError.d.ts +34 -0
- package/dist/esm/review/lineError.d.ts.map +1 -0
- package/dist/esm/review/lineError.js +36 -0
- package/dist/esm/review/lineError.js.map +1 -0
- package/dist/esm/review/messages.d.ts +15 -3
- package/dist/esm/review/messages.d.ts.map +1 -1
- package/dist/esm/review/messages.js +15 -3
- package/dist/esm/review/messages.js.map +1 -1
- package/dist/esm/review/model.d.ts +149 -0
- package/dist/esm/review/model.d.ts.map +1 -0
- package/dist/esm/review/model.js +746 -0
- package/dist/esm/review/model.js.map +1 -0
- package/dist/esm/review/plan.d.ts +63 -0
- package/dist/esm/review/plan.d.ts.map +1 -0
- package/dist/esm/review/plan.js +141 -0
- package/dist/esm/review/plan.js.map +1 -0
- package/dist/esm/review/react/index.d.ts +1 -0
- package/dist/esm/review/react/index.d.ts.map +1 -1
- package/dist/esm/review/react/index.js +1 -0
- package/dist/esm/review/react/index.js.map +1 -1
- package/dist/esm/review/react/useReviewedRun.d.ts +96 -0
- package/dist/esm/review/react/useReviewedRun.d.ts.map +1 -0
- package/dist/esm/review/react/useReviewedRun.js +257 -0
- package/dist/esm/review/react/useReviewedRun.js.map +1 -0
- package/dist/esm/review/receipt.d.ts +4 -1
- package/dist/esm/review/receipt.d.ts.map +1 -1
- package/dist/esm/review/receipt.js +6 -2
- package/dist/esm/review/receipt.js.map +1 -1
- package/dist/esm/review/relayr.d.ts +13 -4
- package/dist/esm/review/relayr.d.ts.map +1 -1
- package/dist/esm/review/relayr.js +50 -8
- package/dist/esm/review/relayr.js.map +1 -1
- package/dist/esm/review/relayrSend.d.ts +135 -0
- package/dist/esm/review/relayrSend.d.ts.map +1 -0
- package/dist/esm/review/relayrSend.js +934 -0
- package/dist/esm/review/relayrSend.js.map +1 -0
- package/dist/esm/review/reviewQueue.d.ts +10 -9
- package/dist/esm/review/reviewQueue.d.ts.map +1 -1
- package/dist/esm/review/reviewQueue.js +17 -26
- package/dist/esm/review/reviewQueue.js.map +1 -1
- package/dist/esm/review/reviewRequests.d.ts +86 -0
- package/dist/esm/review/reviewRequests.d.ts.map +1 -0
- package/dist/esm/review/reviewRequests.js +263 -0
- package/dist/esm/review/reviewRequests.js.map +1 -0
- package/dist/esm/review/safeRelayr.d.ts +3 -1
- package/dist/esm/review/safeRelayr.d.ts.map +1 -1
- package/dist/esm/review/safeRelayr.js +5 -1
- package/dist/esm/review/safeRelayr.js.map +1 -1
- package/dist/esm/review/safeSend.d.ts +69 -0
- package/dist/esm/review/safeSend.d.ts.map +1 -0
- package/dist/esm/review/safeSend.js +303 -0
- package/dist/esm/review/safeSend.js.map +1 -0
- package/dist/esm/review/send.d.ts +241 -0
- package/dist/esm/review/send.d.ts.map +1 -0
- package/dist/esm/review/send.js +1011 -0
- package/dist/esm/review/send.js.map +1 -0
- package/dist/esm/review/sequence.d.ts +77 -0
- package/dist/esm/review/sequence.d.ts.map +1 -0
- package/dist/esm/review/sequence.js +223 -0
- package/dist/esm/review/sequence.js.map +1 -0
- package/dist/esm/review/sign.d.ts +109 -0
- package/dist/esm/review/sign.d.ts.map +1 -0
- package/dist/esm/review/sign.js +368 -0
- package/dist/esm/review/sign.js.map +1 -0
- package/dist/esm/review/simulation.d.ts +41 -2
- package/dist/esm/review/simulation.d.ts.map +1 -1
- package/dist/esm/review/simulation.js +95 -29
- package/dist/esm/review/simulation.js.map +1 -1
- package/dist/esm/review/transaction-message.d.ts +13 -0
- package/dist/esm/review/transaction-message.d.ts.map +1 -1
- package/dist/esm/review/transaction-message.js +23 -0
- package/dist/esm/review/transaction-message.js.map +1 -1
- package/dist/esm/review/transactionReview.d.ts +27 -19
- package/dist/esm/review/transactionReview.d.ts.map +1 -1
- package/dist/esm/review/transactionReview.js +19 -56
- package/dist/esm/review/transactionReview.js.map +1 -1
- package/dist/esm/review/wallet.d.ts +82 -0
- package/dist/esm/review/wallet.d.ts.map +1 -0
- package/dist/esm/review/wallet.js +150 -0
- package/dist/esm/review/wallet.js.map +1 -0
- package/dist/esm/review/writeHold.d.ts +100 -12
- package/dist/esm/review/writeHold.d.ts.map +1 -1
- package/dist/esm/review/writeHold.js +59 -13
- package/dist/esm/review/writeHold.js.map +1 -1
- package/dist/esm/review/writeRecovery.d.ts +6 -1
- package/dist/esm/review/writeRecovery.d.ts.map +1 -1
- package/dist/esm/review/writeRecovery.js +111 -43
- package/dist/esm/review/writeRecovery.js.map +1 -1
- package/dist/esm/safeService.d.ts +27 -4
- package/dist/esm/safeService.d.ts.map +1 -1
- package/dist/esm/safeService.js +119 -4
- package/dist/esm/safeService.js.map +1 -1
- package/dist/esm/testing.d.ts +24 -0
- package/dist/esm/testing.d.ts.map +1 -1
- package/dist/esm/testing.js +23 -1
- package/dist/esm/testing.js.map +1 -1
- package/dist/esm/v6/defifa.d.ts.map +1 -1
- package/dist/esm/v6/defifa.js +24 -23
- package/dist/esm/v6/defifa.js.map +1 -1
- package/dist/esm/v6/executionErrors.d.ts.map +1 -1
- package/dist/esm/v6/executionErrors.js +3 -2
- package/dist/esm/v6/executionErrors.js.map +1 -1
- package/dist/esm/v6/pay.d.ts +25 -8
- package/dist/esm/v6/pay.d.ts.map +1 -1
- package/dist/esm/v6/pay.js +115 -22
- package/dist/esm/v6/pay.js.map +1 -1
- package/dist/esm/v6/suckers.d.ts +30 -0
- package/dist/esm/v6/suckers.d.ts.map +1 -1
- package/dist/esm/v6/suckers.js +67 -5
- package/dist/esm/v6/suckers.js.map +1 -1
- package/package.json +11 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { ReviewLineError } from "./lineError.js";
|
|
2
|
+
import { decodeFunctionData, isAddress, numberToHex, keccak256, } from "viem";
|
|
3
|
+
import { lookAtSafeProposal, readSafeAppExecution, readSafeTransaction, isSafeExecTransaction, safeExecTransactionResult, SAFE_EXEC_ABI, safeProposalFor, safeTransactionMatchesCall, } from "../safeService.js";
|
|
4
|
+
import { MULTI_SEND_CALL_ONLY_DEPLOYMENTS, multiSendCallsOf, readAuthorityIdentity, } from "../safe.js";
|
|
4
5
|
import { TAB } from "./tabState.js";
|
|
5
6
|
import { isBytes32, isHexBytes, uint256 } from "../untrusted.js";
|
|
6
7
|
import { atCanonicalFinalizedBlock, } from "./relayr.js";
|
|
@@ -11,7 +12,7 @@ const TAB_SEEN = TAB.seen;
|
|
|
11
12
|
// failed. It is visible only while the exact durable reservation still exists.
|
|
12
13
|
const unpersistedSubmissions = new WeakMap();
|
|
13
14
|
/** The wallet returned this identity, but storing it failed. Keep it in memory and retry submitted(hash, record). */
|
|
14
|
-
export class SubmittedWritePersistenceError extends
|
|
15
|
+
export class SubmittedWritePersistenceError extends ReviewLineError {
|
|
15
16
|
constructor(record, cause) {
|
|
16
17
|
super("The wallet returned a transaction identity, but recovery storage is unavailable. Keep this transaction pending.");
|
|
17
18
|
this.name = "SubmittedWritePersistenceError";
|
|
@@ -23,7 +24,7 @@ function normalizedIdentity(input) {
|
|
|
23
24
|
if (!Number.isSafeInteger(input?.chainId) ||
|
|
24
25
|
input.chainId <= 0 ||
|
|
25
26
|
!isAddress(input?.account, { strict: false }))
|
|
26
|
-
throw new
|
|
27
|
+
throw new ReviewLineError("Invalid reviewed write recovery evidence.");
|
|
27
28
|
return {
|
|
28
29
|
chainId: input.chainId,
|
|
29
30
|
account: input.account.toLowerCase(),
|
|
@@ -36,7 +37,7 @@ function normalized(input) {
|
|
|
36
37
|
!isAddress(input?.call?.to, { strict: false }) ||
|
|
37
38
|
!isHexBytes(input?.call?.data) ||
|
|
38
39
|
value === null)
|
|
39
|
-
throw new
|
|
40
|
+
throw new ReviewLineError("Invalid reviewed write recovery evidence.");
|
|
40
41
|
return {
|
|
41
42
|
...normalizedIdentity(input),
|
|
42
43
|
safe: input.safe,
|
|
@@ -80,7 +81,7 @@ function recordOf(value) {
|
|
|
80
81
|
(record.executed !== undefined && record.executed !== true) ||
|
|
81
82
|
(record.executionHash !== undefined &&
|
|
82
83
|
(record.executed !== true || !isBytes32(record.executionHash))))
|
|
83
|
-
throw new
|
|
84
|
+
throw new ReviewLineError("Invalid saved write recovery record. Keep this action pending.");
|
|
84
85
|
return {
|
|
85
86
|
version: 1,
|
|
86
87
|
id: record.id,
|
|
@@ -157,7 +158,7 @@ function namespaceOf(value) {
|
|
|
157
158
|
return undefined;
|
|
158
159
|
if (typeof value !== "string" ||
|
|
159
160
|
!/^[a-z0-9][a-z0-9:._/-]{0,127}$/.test(value))
|
|
160
|
-
throw new
|
|
161
|
+
throw new ReviewLineError("Invalid write recovery namespace.");
|
|
161
162
|
return value;
|
|
162
163
|
}
|
|
163
164
|
function namespaceScope(input) {
|
|
@@ -171,7 +172,7 @@ function scope(input) {
|
|
|
171
172
|
function recoveryStorage(store) {
|
|
172
173
|
const result = store ?? globalThis.localStorage;
|
|
173
174
|
if (!result)
|
|
174
|
-
throw new
|
|
175
|
+
throw new ReviewLineError("Write recovery storage is unavailable.");
|
|
175
176
|
return result;
|
|
176
177
|
}
|
|
177
178
|
/** Every key `store` holds: its own `keys()`, or Web Storage's `length` and `key()`. */
|
|
@@ -363,7 +364,7 @@ export function findReviewedWrites(input, options = {}) {
|
|
|
363
364
|
const identity = normalizedIdentity(input);
|
|
364
365
|
if (!isAddress(input.to, { strict: false }) ||
|
|
365
366
|
!/^0x[0-9a-fA-F]{8}$/.test(input.selector))
|
|
366
|
-
throw new
|
|
367
|
+
throw new ReviewLineError("Invalid write hold match.");
|
|
367
368
|
const to = input.to.toLowerCase();
|
|
368
369
|
const selector = input.selector.toLowerCase();
|
|
369
370
|
const store = recoveryStorage(options.storage);
|
|
@@ -401,7 +402,7 @@ function foundAt(input, at) {
|
|
|
401
402
|
(at.startsWith(prefix) &&
|
|
402
403
|
/^\d+:0x[0-9a-f]{64}$/.test(at.slice(prefix.length)))))
|
|
403
404
|
return at;
|
|
404
|
-
throw new
|
|
405
|
+
throw new ReviewLineError("Invalid write recovery key.");
|
|
405
406
|
}
|
|
406
407
|
/**
|
|
407
408
|
* Every unresolved write saved for `account` on `chainId`, with the key it
|
|
@@ -449,7 +450,7 @@ export function readBrowserWriteRecovery(input, options = {}) {
|
|
|
449
450
|
const identity = normalizedIdentity(input);
|
|
450
451
|
const namespace = namespaceOf(input?.namespace);
|
|
451
452
|
if (namespace === undefined)
|
|
452
|
-
throw new
|
|
453
|
+
throw new ReviewLineError("Provide a write recovery namespace.");
|
|
453
454
|
return readRecovery(recoveryStorage(options.storage), namespaceScope({ ...identity, namespace }));
|
|
454
455
|
}
|
|
455
456
|
/**
|
|
@@ -460,12 +461,20 @@ export function readBrowserWriteRecovery(input, options = {}) {
|
|
|
460
461
|
function releasedKey(key, id) {
|
|
461
462
|
return `${key}:released:${id}`;
|
|
462
463
|
}
|
|
464
|
+
/**
|
|
465
|
+
* The key that marks the record `id` saved at `key` as ended by the user's
|
|
466
|
+
* exit or as never sent, never by a settlement's cleanup: only it lets a
|
|
467
|
+
* saved sequence send that step again.
|
|
468
|
+
*/
|
|
469
|
+
function exitedKey(key, id) {
|
|
470
|
+
return `${key}:exited:${id}`;
|
|
471
|
+
}
|
|
463
472
|
function readStored(raw, key, scopeOf = scope, store) {
|
|
464
473
|
if (raw === null)
|
|
465
474
|
return null;
|
|
466
475
|
const record = recordOf(JSON.parse(raw));
|
|
467
476
|
if (scopeOf(record) !== key)
|
|
468
|
-
throw new
|
|
477
|
+
throw new ReviewLineError("Saved write recovery scope does not match.");
|
|
469
478
|
if (store && store.getItem(releasedKey(key, record.id)) !== null)
|
|
470
479
|
return null;
|
|
471
480
|
return record;
|
|
@@ -690,7 +699,7 @@ export function createBrowserWriteRecovery(input, options = {}) {
|
|
|
690
699
|
}
|
|
691
700
|
function requireLock() {
|
|
692
701
|
if (!locked)
|
|
693
|
-
throw new
|
|
702
|
+
throw new ReviewLineError("Write recovery changes require the browser lock.");
|
|
694
703
|
}
|
|
695
704
|
function read() {
|
|
696
705
|
const store = storage();
|
|
@@ -702,7 +711,7 @@ export function createBrowserWriteRecovery(input, options = {}) {
|
|
|
702
711
|
const store = storage();
|
|
703
712
|
store.setItem(at, raw);
|
|
704
713
|
if (store.getItem(at) !== raw)
|
|
705
|
-
throw new
|
|
714
|
+
throw new ReviewLineError("Write recovery storage did not retain the action.");
|
|
706
715
|
}
|
|
707
716
|
function clear(expected) {
|
|
708
717
|
requireLock();
|
|
@@ -718,7 +727,7 @@ export function createBrowserWriteRecovery(input, options = {}) {
|
|
|
718
727
|
if (!current)
|
|
719
728
|
return;
|
|
720
729
|
if (JSON.stringify(current) !== JSON.stringify(recordOf(expected))) {
|
|
721
|
-
throw new
|
|
730
|
+
throw new ReviewLineError("Write recovery changed. Keep the current action pending.");
|
|
722
731
|
}
|
|
723
732
|
// The last record of an attempt goes only once its generation is the
|
|
724
733
|
// committed latest marker; otherwise it stays, released, and carries it.
|
|
@@ -726,13 +735,13 @@ export function createBrowserWriteRecovery(input, options = {}) {
|
|
|
726
735
|
const marker = releasedKey(at, current.id);
|
|
727
736
|
store.setItem(marker, "1");
|
|
728
737
|
if (store.getItem(marker) !== "1")
|
|
729
|
-
throw new
|
|
738
|
+
throw new ReviewLineError("Write recovery storage did not clear the action.");
|
|
730
739
|
unpersistedSubmissions.get(store)?.delete(at);
|
|
731
740
|
return;
|
|
732
741
|
}
|
|
733
742
|
store.removeItem(at);
|
|
734
743
|
if (store.getItem(at) !== null)
|
|
735
|
-
throw new
|
|
744
|
+
throw new ReviewLineError("Write recovery storage did not clear the action.");
|
|
736
745
|
unpersistedSubmissions.get(store)?.delete(at);
|
|
737
746
|
}
|
|
738
747
|
/** Add `fields` to exactly `expected`, a hashed record `when` allows; extra evidence only. */
|
|
@@ -760,6 +769,12 @@ export function createBrowserWriteRecovery(input, options = {}) {
|
|
|
760
769
|
const current = read();
|
|
761
770
|
if (current?.id === owned.id && current.hash)
|
|
762
771
|
return;
|
|
772
|
+
try {
|
|
773
|
+
storage().setItem(exitedKey(locate(storage()).at, owned.id), "1");
|
|
774
|
+
}
|
|
775
|
+
catch {
|
|
776
|
+
/* Unsaved, a sequence resumed over it asks for the user's check. */
|
|
777
|
+
}
|
|
763
778
|
// Removing the record must not uncover a settlement of an earlier
|
|
764
779
|
// attempt: unless this reservation is the verified latest, it stays as
|
|
765
780
|
// released instead, which still invalidates that settlement.
|
|
@@ -815,13 +830,13 @@ export function createBrowserWriteRecovery(input, options = {}) {
|
|
|
815
830
|
function record(hash, expected, replace) {
|
|
816
831
|
requireLock();
|
|
817
832
|
if (!isBytes32(hash))
|
|
818
|
-
throw new
|
|
833
|
+
throw new ReviewLineError("The wallet returned an invalid transaction identity.");
|
|
819
834
|
const previous = expected && recordOf(expected);
|
|
820
835
|
const submittedHash = hash.toLowerCase();
|
|
821
836
|
if (!previous ||
|
|
822
837
|
keyOf(previous) !== key ||
|
|
823
838
|
(!replace && previous.hash && previous.hash !== submittedHash)) {
|
|
824
|
-
throw new
|
|
839
|
+
throw new ReviewLineError("Write recovery changed before submission was recorded.");
|
|
825
840
|
}
|
|
826
841
|
// A hash the wallet returns now starts its clock; a speed-up found at its nonce keeps it.
|
|
827
842
|
const submittedAt = replace || previous.hash === submittedHash
|
|
@@ -858,7 +873,7 @@ export function createBrowserWriteRecovery(input, options = {}) {
|
|
|
858
873
|
submittedAt: undefined,
|
|
859
874
|
}) ||
|
|
860
875
|
(!replace && current.hash && current.hash !== submittedHash)) {
|
|
861
|
-
throw new
|
|
876
|
+
throw new ReviewLineError("Write recovery changed before submission was recorded.");
|
|
862
877
|
}
|
|
863
878
|
owned = recordOf(submitted);
|
|
864
879
|
if (current.hash !== submittedHash) {
|
|
@@ -892,15 +907,15 @@ export function createBrowserWriteRecovery(input, options = {}) {
|
|
|
892
907
|
? normalized({ ...reviewed, call: actualCall })
|
|
893
908
|
: reviewed;
|
|
894
909
|
if (legacyScope(actual) !== legacyScope(reviewed))
|
|
895
|
-
throw new
|
|
910
|
+
throw new ReviewLineError("The adopted write has a different recovery scope.");
|
|
896
911
|
const nonce = evidence && uint256(evidence.nonce);
|
|
897
912
|
const fromBlock = evidence && uint256(evidence.blockNumber);
|
|
898
913
|
if (evidence && (nonce === null || fromBlock === null))
|
|
899
|
-
throw new
|
|
914
|
+
throw new ReviewLineError("Invalid write recovery nonce evidence.");
|
|
900
915
|
const store = storage();
|
|
901
916
|
const { at, raw } = locate(store);
|
|
902
917
|
if (readRecovery(store, at, raw, scopeAt(at)))
|
|
903
|
-
throw new
|
|
918
|
+
throw new ReviewLineError("An earlier wallet write is still unresolved. Check it before trying again.");
|
|
904
919
|
// The record this one replaces, if the user released it: its marker goes too.
|
|
905
920
|
let replaced;
|
|
906
921
|
try {
|
|
@@ -939,6 +954,7 @@ export function createBrowserWriteRecovery(input, options = {}) {
|
|
|
939
954
|
if (typeof replaced === "string" && replaced !== record.id)
|
|
940
955
|
try {
|
|
941
956
|
store.removeItem(releasedKey(key, replaced));
|
|
957
|
+
store.removeItem(exitedKey(key, replaced));
|
|
942
958
|
}
|
|
943
959
|
catch {
|
|
944
960
|
/* A leftover marker names only the old record. */
|
|
@@ -971,7 +987,7 @@ export function createBrowserWriteRecovery(input, options = {}) {
|
|
|
971
987
|
requireLock();
|
|
972
988
|
const current = read();
|
|
973
989
|
if (current && current.mirrorOf !== of)
|
|
974
|
-
throw new
|
|
990
|
+
throw new ReviewLineError("An earlier wallet write is still unresolved. Check it before trying again.");
|
|
975
991
|
const mirrored = recordOf({
|
|
976
992
|
version: 1,
|
|
977
993
|
id: source.id,
|
|
@@ -1011,6 +1027,16 @@ export function createBrowserWriteRecovery(input, options = {}) {
|
|
|
1011
1027
|
return undefined;
|
|
1012
1028
|
}
|
|
1013
1029
|
},
|
|
1030
|
+
/** Whether the record `id` ended by the user's exit, or because nothing was sent. */
|
|
1031
|
+
released(id) {
|
|
1032
|
+
try {
|
|
1033
|
+
const store = storage();
|
|
1034
|
+
return store.getItem(exitedKey(locate(store).at, id)) !== null;
|
|
1035
|
+
}
|
|
1036
|
+
catch {
|
|
1037
|
+
return false;
|
|
1038
|
+
}
|
|
1039
|
+
},
|
|
1014
1040
|
/**
|
|
1015
1041
|
* The call's latest reservation id: the record saved at the key (held,
|
|
1016
1042
|
* or released by its exit), or else the saved latest marker.
|
|
@@ -1271,7 +1297,7 @@ export function createBrowserWriteRecovery(input, options = {}) {
|
|
|
1271
1297
|
executed(expected, executionHash) {
|
|
1272
1298
|
requireLock();
|
|
1273
1299
|
if (executionHash !== undefined && !isBytes32(executionHash))
|
|
1274
|
-
throw new
|
|
1300
|
+
throw new ReviewLineError("Invalid execution transaction identity.");
|
|
1275
1301
|
const store = storage();
|
|
1276
1302
|
const { at, raw } = locate(store);
|
|
1277
1303
|
const current = readRecovery(store, at, raw, scopeAt(at));
|
|
@@ -1279,7 +1305,7 @@ export function createBrowserWriteRecovery(input, options = {}) {
|
|
|
1279
1305
|
if (!current?.hash ||
|
|
1280
1306
|
current.id !== wanted.id ||
|
|
1281
1307
|
current.hash !== wanted.hash)
|
|
1282
|
-
throw new
|
|
1308
|
+
throw new ReviewLineError("Write recovery changed. Keep the current action pending.");
|
|
1283
1309
|
const next = recordOf({
|
|
1284
1310
|
...current,
|
|
1285
1311
|
executed: true,
|
|
@@ -1318,7 +1344,7 @@ export function createBrowserWriteRecovery(input, options = {}) {
|
|
|
1318
1344
|
*/
|
|
1319
1345
|
abandon(expected, acknowledgement) {
|
|
1320
1346
|
if (acknowledgement?.checkedWallet !== true)
|
|
1321
|
-
throw new
|
|
1347
|
+
throw new ReviewLineError("Release a held write only after the user confirms they checked their wallet.");
|
|
1322
1348
|
const wanted = JSON.stringify(recordOf(expected));
|
|
1323
1349
|
const store = storage();
|
|
1324
1350
|
const { at, raw } = locate(store);
|
|
@@ -1326,15 +1352,21 @@ export function createBrowserWriteRecovery(input, options = {}) {
|
|
|
1326
1352
|
if (!durable)
|
|
1327
1353
|
return;
|
|
1328
1354
|
if (durable.executed)
|
|
1329
|
-
throw new
|
|
1355
|
+
throw new ReviewLineError("This write ran onchain. Keep it held until its result is known.");
|
|
1330
1356
|
const shown = readRecovery(store, at, raw, scopeAt(at));
|
|
1331
1357
|
if (JSON.stringify(durable) !== wanted &&
|
|
1332
1358
|
JSON.stringify(shown) !== wanted)
|
|
1333
|
-
throw new
|
|
1359
|
+
throw new ReviewLineError("Write recovery changed. Keep the current action pending.");
|
|
1334
1360
|
const marker = releasedKey(at, durable.id);
|
|
1361
|
+
try {
|
|
1362
|
+
store.setItem(exitedKey(at, durable.id), "1");
|
|
1363
|
+
}
|
|
1364
|
+
catch {
|
|
1365
|
+
/* Unsaved, a sequence resumed over it asks for the user's check. */
|
|
1366
|
+
}
|
|
1335
1367
|
store.setItem(marker, "1");
|
|
1336
1368
|
if (store.getItem(marker) !== "1")
|
|
1337
|
-
throw new
|
|
1369
|
+
throw new ReviewLineError("Write recovery storage did not release the action.");
|
|
1338
1370
|
const memory = unpersistedSubmissions.get(store);
|
|
1339
1371
|
if (memory?.get(at)?.id === durable.id)
|
|
1340
1372
|
memory.delete(at);
|
|
@@ -1345,7 +1377,7 @@ export function createBrowserWriteRecovery(input, options = {}) {
|
|
|
1345
1377
|
const locks = options.locks ?? browserLocks();
|
|
1346
1378
|
return locks.request(key, { mode: "exclusive", ...(!wait && { ifAvailable: true }) }, async (lock) => {
|
|
1347
1379
|
if (!lock)
|
|
1348
|
-
throw new
|
|
1380
|
+
throw new ReviewLineError("This wallet action is already open in another tab.");
|
|
1349
1381
|
locked = true;
|
|
1350
1382
|
try {
|
|
1351
1383
|
return await work();
|
|
@@ -1503,7 +1535,13 @@ function heldBatch(record) {
|
|
|
1503
1535
|
: null;
|
|
1504
1536
|
return inner && inner.map((call) => normalized({ ...record, call }).call);
|
|
1505
1537
|
}
|
|
1506
|
-
/**
|
|
1538
|
+
/**
|
|
1539
|
+
* The MultiSend targets a held batch may run through: a Safe app folds the
|
|
1540
|
+
* same calls into its own version's MultiSendCallOnly, so any recognized
|
|
1541
|
+
* deployment carries exactly the held calldata.
|
|
1542
|
+
*/
|
|
1543
|
+
const BATCH_TARGETS = MULTI_SEND_CALL_ONLY_DEPLOYMENTS.map((to) => to.toLowerCase());
|
|
1544
|
+
/** Whether `transaction` is the Safe's execTransaction of exactly the held batch: a recognized MultiSendCallOnly, its calldata, zero value and DELEGATECALL. */
|
|
1507
1545
|
function runsHeldBatch(transaction, record) {
|
|
1508
1546
|
try {
|
|
1509
1547
|
const { functionName, args } = decodeFunctionData({
|
|
@@ -1513,7 +1551,7 @@ function runsHeldBatch(transaction, record) {
|
|
|
1513
1551
|
if (functionName !== "execTransaction")
|
|
1514
1552
|
return false;
|
|
1515
1553
|
const [to, value, data, operation] = args;
|
|
1516
|
-
return (to.toLowerCase()
|
|
1554
|
+
return (BATCH_TARGETS.includes(to.toLowerCase()) &&
|
|
1517
1555
|
value === 0n &&
|
|
1518
1556
|
data.toLowerCase() === record.call.data &&
|
|
1519
1557
|
operation === 1);
|
|
@@ -1539,13 +1577,14 @@ export function heldSafeProposal(input, nonce) {
|
|
|
1539
1577
|
*/
|
|
1540
1578
|
export function safeProposalIsHeldCall(proposal, input) {
|
|
1541
1579
|
const record = normalized(input);
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
:
|
|
1548
|
-
|
|
1580
|
+
const call = { ...record.call, value: BigInt(record.call.value) };
|
|
1581
|
+
return heldBatch({ ...record, version: 1, id: "" })
|
|
1582
|
+
? BATCH_TARGETS.some((to) => safeTransactionMatchesCall(proposal, {
|
|
1583
|
+
...call,
|
|
1584
|
+
to: to,
|
|
1585
|
+
operation: 1,
|
|
1586
|
+
}))
|
|
1587
|
+
: safeTransactionMatchesCall(proposal, call);
|
|
1549
1588
|
}
|
|
1550
1589
|
/**
|
|
1551
1590
|
* Authenticate the saved wallet identity, canonical inclusion and Safe effect.
|
|
@@ -1559,7 +1598,7 @@ export function safeProposalIsHeldCall(proposal, input) {
|
|
|
1559
1598
|
*/
|
|
1560
1599
|
export async function verifyReviewedWriteReceipt(client, saved, receipt, proof, { finality = true } = {}) {
|
|
1561
1600
|
const record = recordOf(saved);
|
|
1562
|
-
const pending = () => new
|
|
1601
|
+
const pending = () => new ReviewLineError("The saved wallet write is not yet proven. Keep this action pending.");
|
|
1563
1602
|
// A batch hold's call is its MultiSend: its proof is the calls it encodes.
|
|
1564
1603
|
const batch = heldBatch(record);
|
|
1565
1604
|
let calls = batch ?? [record.call];
|
|
@@ -1646,6 +1685,35 @@ export async function verifyReviewedWriteReceipt(client, saved, receipt, proof,
|
|
|
1646
1685
|
throw pending();
|
|
1647
1686
|
status = result.status;
|
|
1648
1687
|
}
|
|
1688
|
+
else if (status === "success" && isSafeExecTransaction(record.call.data)) {
|
|
1689
|
+
// A Safe's execTransaction succeeds only with the Safe's own
|
|
1690
|
+
// ExecutionSuccess for its exact hash: an ExecutionFailure, or no event
|
|
1691
|
+
// for it, is a failure whatever the receipt's status. A call that only
|
|
1692
|
+
// shares the selector, to anything but a Safe, is decided as any other.
|
|
1693
|
+
if (!client.request)
|
|
1694
|
+
throw pending();
|
|
1695
|
+
const { request } = client;
|
|
1696
|
+
const at = (blockNumber) => blockNumber === undefined ? "latest" : numberToHex(blockNumber);
|
|
1697
|
+
// Every read through the one `request` the receipt client has.
|
|
1698
|
+
const identity = await readAuthorityIdentity({
|
|
1699
|
+
request,
|
|
1700
|
+
getCode: ({ address, blockNumber }) => request({
|
|
1701
|
+
method: "eth_getCode",
|
|
1702
|
+
params: [address, at(blockNumber)],
|
|
1703
|
+
}),
|
|
1704
|
+
getStorageAt: ({ address, slot, blockNumber }) => request({
|
|
1705
|
+
method: "eth_getStorageAt",
|
|
1706
|
+
params: [address, slot, at(blockNumber)],
|
|
1707
|
+
}),
|
|
1708
|
+
}, record.call.to, { blockNumber: canonical.blockNumber });
|
|
1709
|
+
if (!identity)
|
|
1710
|
+
throw pending();
|
|
1711
|
+
if (identity.kind === "safe") {
|
|
1712
|
+
const execution = await safeExecTransactionResult({ request: client.request }, record.chainId, record.call.to, record.call.data, canonical);
|
|
1713
|
+
if (execution?.status !== "success")
|
|
1714
|
+
status = "failed";
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1649
1717
|
const isCanonical = async () => {
|
|
1650
1718
|
const block = await client.getBlock({ blockNumber: canonical.blockNumber });
|
|
1651
1719
|
return (block.number === canonical.blockNumber &&
|
|
@@ -1666,7 +1734,7 @@ export async function verifyReviewedWriteReceipt(client, saved, receipt, proof,
|
|
|
1666
1734
|
*/
|
|
1667
1735
|
export async function verifyReviewedWriteExpiry(client, saved, service) {
|
|
1668
1736
|
const record = recordOf(saved);
|
|
1669
|
-
const pending = () => new
|
|
1737
|
+
const pending = () => new ReviewLineError("The saved Safe proposal is not proven expired. Keep this action pending.");
|
|
1670
1738
|
if (!record.safe ||
|
|
1671
1739
|
!record.hash ||
|
|
1672
1740
|
(await client.getChainId()) !== record.chainId)
|