@bananapus/nana-sdk-core 2.24.4 → 2.25.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/jbcenter/publish.d.ts +6 -5
- package/dist/cjs/jbcenter/publish.d.ts.map +1 -1
- package/dist/cjs/jbcenter/publish.js +37 -18
- package/dist/cjs/jbcenter/publish.js.map +1 -1
- package/dist/cjs/jbcenter/rateLimit.d.ts +12 -2
- package/dist/cjs/jbcenter/rateLimit.d.ts.map +1 -1
- package/dist/cjs/jbcenter/rateLimit.js +20 -3
- package/dist/cjs/jbcenter/rateLimit.js.map +1 -1
- package/dist/cjs/jbcenter.d.ts +1 -1
- package/dist/cjs/jbcenter.d.ts.map +1 -1
- package/dist/cjs/jbcenter.js +2 -1
- package/dist/cjs/jbcenter.js.map +1 -1
- package/dist/cjs/review/contractWrite.d.ts +3 -1
- package/dist/cjs/review/contractWrite.d.ts.map +1 -1
- package/dist/cjs/review/contractWrite.js +13 -11
- package/dist/cjs/review/contractWrite.js.map +1 -1
- package/dist/cjs/review/index.d.ts +1 -0
- package/dist/cjs/review/index.d.ts.map +1 -1
- package/dist/cjs/review/index.js +1 -0
- package/dist/cjs/review/index.js.map +1 -1
- package/dist/cjs/review/relayr.d.ts +54 -12
- package/dist/cjs/review/relayr.d.ts.map +1 -1
- package/dist/cjs/review/relayr.js +175 -43
- package/dist/cjs/review/relayr.js.map +1 -1
- package/dist/cjs/review/safeRelayr.d.ts +1 -1
- package/dist/cjs/review/safeRelayr.d.ts.map +1 -1
- package/dist/cjs/review/safeRelayr.js +27 -3
- package/dist/cjs/review/safeRelayr.js.map +1 -1
- package/dist/cjs/review/transaction-message.d.ts +3 -0
- package/dist/cjs/review/transaction-message.d.ts.map +1 -0
- package/dist/cjs/review/transaction-message.js +19 -0
- package/dist/cjs/review/transaction-message.js.map +1 -0
- package/dist/cjs/safeService.d.ts +152 -1
- package/dist/cjs/safeService.d.ts.map +1 -1
- package/dist/cjs/safeService.js +325 -1
- package/dist/cjs/safeService.js.map +1 -1
- package/dist/esm/jbcenter/publish.d.ts +6 -5
- package/dist/esm/jbcenter/publish.d.ts.map +1 -1
- package/dist/esm/jbcenter/publish.js +37 -18
- package/dist/esm/jbcenter/publish.js.map +1 -1
- package/dist/esm/jbcenter/rateLimit.d.ts +12 -2
- package/dist/esm/jbcenter/rateLimit.d.ts.map +1 -1
- package/dist/esm/jbcenter/rateLimit.js +19 -3
- package/dist/esm/jbcenter/rateLimit.js.map +1 -1
- package/dist/esm/jbcenter.d.ts +1 -1
- package/dist/esm/jbcenter.d.ts.map +1 -1
- package/dist/esm/jbcenter.js +1 -1
- package/dist/esm/jbcenter.js.map +1 -1
- package/dist/esm/review/contractWrite.d.ts +3 -1
- package/dist/esm/review/contractWrite.d.ts.map +1 -1
- package/dist/esm/review/contractWrite.js +13 -11
- package/dist/esm/review/contractWrite.js.map +1 -1
- package/dist/esm/review/index.d.ts +1 -0
- package/dist/esm/review/index.d.ts.map +1 -1
- package/dist/esm/review/index.js +1 -0
- package/dist/esm/review/index.js.map +1 -1
- package/dist/esm/review/relayr.d.ts +54 -12
- package/dist/esm/review/relayr.d.ts.map +1 -1
- package/dist/esm/review/relayr.js +170 -42
- package/dist/esm/review/relayr.js.map +1 -1
- package/dist/esm/review/safeRelayr.d.ts +1 -1
- package/dist/esm/review/safeRelayr.d.ts.map +1 -1
- package/dist/esm/review/safeRelayr.js +28 -4
- package/dist/esm/review/safeRelayr.js.map +1 -1
- package/dist/esm/review/transaction-message.d.ts +3 -0
- package/dist/esm/review/transaction-message.d.ts.map +1 -0
- package/dist/esm/review/transaction-message.js +16 -0
- package/dist/esm/review/transaction-message.js.map +1 -0
- package/dist/esm/safeService.d.ts +152 -1
- package/dist/esm/safeService.d.ts.map +1 -1
- package/dist/esm/safeService.js +314 -2
- package/dist/esm/safeService.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Address, type Hex } from "viem";
|
|
2
|
-
import { type SafeCreation } from "./safe.js";
|
|
2
|
+
import { readBoundedSafeNonce, type SafeCreation } from "./safe.js";
|
|
3
3
|
/**
|
|
4
4
|
* Safe's per-chain app URL prefix. Wider than {@link SAFE_SERVICE_PREFIX}:
|
|
5
5
|
* Safe app links work on chains without a hosted transaction service.
|
|
@@ -287,6 +287,157 @@ export declare function safeExecutionResult(receipt: {
|
|
|
287
287
|
}, safe: Address, hash: Hex): SafeExecutionResult;
|
|
288
288
|
/** Throws unless `receipt` proves the Safe transaction `hash` ran and succeeded ({@link safeExecutionResult}). */
|
|
289
289
|
export declare function requireSafeExecutionSuccess(receipt: Parameters<typeof safeExecutionResult>[0], safe: Address, hash: Hex): void;
|
|
290
|
+
/** What a Safe app flow says when it cannot confirm its proposal ran. */
|
|
291
|
+
export declare const SAFE_PROPOSAL_UNCONFIRMED = "Safe proposal submitted, but confirmation is unavailable. Check Safe before taking another action.";
|
|
292
|
+
/** What a Safe app flow says while its proposal waits for the Safe's other signers. */
|
|
293
|
+
export declare const SAFE_PROPOSAL_AWAITING = "Proposed to your Safe. Its other signers can approve it there.";
|
|
294
|
+
/** A call a Safe app proposal was reviewed to run. */
|
|
295
|
+
export type SafeAppCall = {
|
|
296
|
+
to: Address;
|
|
297
|
+
data: Hex;
|
|
298
|
+
value?: bigint;
|
|
299
|
+
};
|
|
300
|
+
/** A reviewed call whose wei value may be persisted as a decimal string. */
|
|
301
|
+
export type ReviewedSafeCall = Omit<SafeAppCall, "value"> & {
|
|
302
|
+
value?: bigint | string;
|
|
303
|
+
};
|
|
304
|
+
type SafeAppExecution = {
|
|
305
|
+
/** Reads the execution's transaction, which only an execution returned at once needs. */
|
|
306
|
+
client: {
|
|
307
|
+
getTransaction(args: {
|
|
308
|
+
hash: Hex;
|
|
309
|
+
}): Promise<{
|
|
310
|
+
to?: Address | null;
|
|
311
|
+
input?: Hex;
|
|
312
|
+
}>;
|
|
313
|
+
};
|
|
314
|
+
receipt: Parameters<typeof safeExecutionResult>[0];
|
|
315
|
+
safe: Address;
|
|
316
|
+
/** What the wallet returned: the safeTxHash, or the execution's own hash when Safe{Wallet} executed at once. */
|
|
317
|
+
proposalHash: Hex;
|
|
318
|
+
/** What the proposal was reviewed to run: one call, or a batch in order. */
|
|
319
|
+
calls: readonly ReviewedSafeCall[];
|
|
320
|
+
/** Whether a recognized MultiSendCallOnly batch may run the calls. */
|
|
321
|
+
batch?: boolean;
|
|
322
|
+
};
|
|
323
|
+
/**
|
|
324
|
+
* Whether the Safe transaction runs exactly the reviewed calls: one CALL,
|
|
325
|
+
* or, when `batch` permits it, a zero-value MultiSendCallOnly DELEGATECALL
|
|
326
|
+
* running every call in order. Persisted decimal values compare in wei.
|
|
327
|
+
*/
|
|
328
|
+
export declare function safeTransactionRunsCalls(tx: {
|
|
329
|
+
to: Address;
|
|
330
|
+
value: bigint;
|
|
331
|
+
data: Hex;
|
|
332
|
+
operation: number;
|
|
333
|
+
}, calls: readonly ReviewedSafeCall[], batch?: boolean): boolean;
|
|
334
|
+
/** Whether a transaction calls `safe`'s execTransaction of exactly the reviewed calls. */
|
|
335
|
+
export declare function safeExecutionRunsCalls(transaction: {
|
|
336
|
+
to?: Address | null;
|
|
337
|
+
input?: Hex;
|
|
338
|
+
}, safe: Address, calls: readonly ReviewedSafeCall[], batch?: boolean): boolean;
|
|
339
|
+
/**
|
|
340
|
+
* What the execution's receipt proves about the proposal a Safe app returned
|
|
341
|
+
* ({@link safeExecutionResult}). When Safe{Wallet} executed it at once, the
|
|
342
|
+
* reply is the execution's own hash and the SDK takes the Safe's one
|
|
343
|
+
* execution event in that receipt whatever its safeTxHash, so the execution
|
|
344
|
+
* must also be the Safe's execTransaction of exactly the reviewed calls, or
|
|
345
|
+
* the result is unproven.
|
|
346
|
+
*/
|
|
347
|
+
export declare function readSafeAppExecution({ client, receipt, safe, proposalHash, calls, batch, }: SafeAppExecution): Promise<SafeExecutionResult>;
|
|
348
|
+
/**
|
|
349
|
+
* Throws unless the execution proves the Safe ran the reviewed proposal and
|
|
350
|
+
* its call succeeded ({@link readSafeAppExecution}): `failure` when the Safe
|
|
351
|
+
* ran it and it failed, and SAFE_PROPOSAL_UNCONFIRMED when it does not show
|
|
352
|
+
* this proposal ran.
|
|
353
|
+
*/
|
|
354
|
+
export declare function requireSafeProposalSuccess(execution: SafeAppExecution, failure: string): Promise<void>;
|
|
355
|
+
/**
|
|
356
|
+
* The call a Safe proposal of `call` holds: `call` with the field it is
|
|
357
|
+
* stamped with at send time zeroed, so the same action sent again with a later
|
|
358
|
+
* stamp is the action the proposal already holds. Any other call is held
|
|
359
|
+
* exactly as sent.
|
|
360
|
+
*/
|
|
361
|
+
export declare function heldCall(call: SafeAppCall): SafeAppCall;
|
|
362
|
+
/** The deadline after which the contract refuses `call`, or null for a call without one. */
|
|
363
|
+
export declare function stampedDeadline(call: SafeAppCall): bigint | null;
|
|
364
|
+
/** A chain client that reads the Safe's nonce and the latest block. */
|
|
365
|
+
type SafeQueueClient = Parameters<typeof readBoundedSafeNonce>[0] & {
|
|
366
|
+
getBlock(): Promise<{
|
|
367
|
+
number: bigint | null;
|
|
368
|
+
timestamp: bigint;
|
|
369
|
+
}>;
|
|
370
|
+
};
|
|
371
|
+
/**
|
|
372
|
+
* A pending proposal of the action `call` makes in `safe`'s queue (its
|
|
373
|
+
* service record, its safeTxHash and the call it runs), read from Safe's
|
|
374
|
+
* service from the Safe's nonce in the latest block, or null: a Safe app
|
|
375
|
+
* never proposes an action that is already queued, whoever queued it,
|
|
376
|
+
* whatever its stamp ({@link heldCall}). A queued call the contract refuses
|
|
377
|
+
* once its deadline passed is passed over when that block is past the
|
|
378
|
+
* deadline: it can no longer run. Throws when the block, the nonce or the
|
|
379
|
+
* queue can't be read.
|
|
380
|
+
*/
|
|
381
|
+
export declare function findPendingSafeAppProposal(client: SafeQueueClient, chainId: number, safe: Address, call: SafeAppCall, service?: SafeServiceOptions): Promise<{
|
|
382
|
+
tx: SafeQueuedTransaction;
|
|
383
|
+
proposalHash: Hex;
|
|
384
|
+
call: SafeAppCall;
|
|
385
|
+
} | null>;
|
|
386
|
+
/**
|
|
387
|
+
* What one look at a proposal awaiting its signers finds:
|
|
388
|
+
*
|
|
389
|
+
* - `expired`: the latest block is past its deadline and the Safe's nonce in
|
|
390
|
+
* that block is not past the proposal's, so it never ran, and the contract
|
|
391
|
+
* refuses it in any later block;
|
|
392
|
+
* - `passed`: the Safe's nonce is past the proposal's and Safe's service lists
|
|
393
|
+
* no execution of it: another transaction took its nonce, or the service has
|
|
394
|
+
* yet to list its own execution;
|
|
395
|
+
* - `live`: it can still run, it ran, or the look could not tell.
|
|
396
|
+
*/
|
|
397
|
+
export type SafeProposalLook = "expired" | "passed" | "live";
|
|
398
|
+
/**
|
|
399
|
+
* One look at `safe`'s proposal `proposalHash`: the latest block, the Safe's
|
|
400
|
+
* nonce in that block, and Safe's authenticated record of the proposal. A read
|
|
401
|
+
* that fails makes the look live.
|
|
402
|
+
*/
|
|
403
|
+
export declare function lookAtSafeProposal(client: SafeQueueClient, chainId: number, safe: Address, proposalHash: Hex, service?: SafeServiceOptions): Promise<SafeProposalLook>;
|
|
404
|
+
/**
|
|
405
|
+
* Watches a proposal awaiting its signers, one {@link lookAtSafeProposal} a
|
|
406
|
+
* minute, until `signal` aborts. It ends `expired` at the first look that
|
|
407
|
+
* finds it expired, and `replaced` once looks in a row have found it passed
|
|
408
|
+
* for ten minutes: one such look proves nothing, since Safe's service may list
|
|
409
|
+
* the proposal's own execution later. Any other look starts that count again.
|
|
410
|
+
*/
|
|
411
|
+
export declare function watchSafeProposal(client: SafeQueueClient, chainId: number, safe: Address, proposalHash: Hex, signal: AbortSignal, service?: SafeServiceOptions): Promise<"expired" | "replaced">;
|
|
412
|
+
/**
|
|
413
|
+
* The transaction `hash` names on the chain, or null: Safe{Wallet} replies
|
|
414
|
+
* with the execution's own hash when the owner executes at once, and the node
|
|
415
|
+
* may learn it a moment later. It looks up to 5 times, 2 seconds apart (8
|
|
416
|
+
* seconds at most), before the reply counts as a proposal.
|
|
417
|
+
*/
|
|
418
|
+
export declare function atOnceExecution<T>(client: {
|
|
419
|
+
getTransaction(args: {
|
|
420
|
+
hash: Hex;
|
|
421
|
+
}): Promise<T>;
|
|
422
|
+
}, hash: Hex): Promise<T | null>;
|
|
423
|
+
/**
|
|
424
|
+
* The chain's last word before a proposal ends unproven: what `read` returns,
|
|
425
|
+
* or null when the chain says there is none (viem's transaction or receipt
|
|
426
|
+
* not-found). A node that can't answer says nothing, so it is asked again a
|
|
427
|
+
* minute later, for as long as it takes, with `onRetry` called first. With
|
|
428
|
+
* `exists`, the chain already proved the thing exists (its receipt is in
|
|
429
|
+
* hand), so a not-found only says the node is behind, and is asked again too.
|
|
430
|
+
*/
|
|
431
|
+
export declare function chainAnswer<T>(read: () => Promise<T>, { exists, onRetry }?: {
|
|
432
|
+
exists?: boolean;
|
|
433
|
+
onRetry?: () => void;
|
|
434
|
+
}): Promise<T | null>;
|
|
435
|
+
/**
|
|
436
|
+
* The execution Safe's authenticated record names for `safeTxHash` when
|
|
437
|
+
* `error` is its service's report that the proposal ran and failed, or null.
|
|
438
|
+
* Only that execution's receipt decides the proposal, never the report alone.
|
|
439
|
+
*/
|
|
440
|
+
export declare function reportedSafeExecution(error: unknown, chainId: number, safe: Address, safeTxHash: Hex, service?: SafeServiceOptions): Promise<Hex | null>;
|
|
290
441
|
/**
|
|
291
442
|
* The confirmations of `tx` that count: one per current owner in `owners`,
|
|
292
443
|
* with a well-formed signature or none (an onchain approval), a signature
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safeService.d.ts","sourceRoot":"","sources":["../../src/safeService.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"safeService.d.ts","sourceRoot":"","sources":["../../src/safeService.ts"],"names":[],"mappings":"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"}
|
package/dist/cjs/safeService.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SAFE_SERVICE_MAX_RETRY_WAIT_MS = exports.SAFE_EXEC_ABI = exports.SAFE_TX_TYPES = exports.SAFE_NONCE_GUIDANCE = exports.SAFE_SERVICE_PREFIX = exports.SAFE_PREFIX = void 0;
|
|
3
|
+
exports.SAFE_SERVICE_MAX_RETRY_WAIT_MS = exports.SAFE_PROPOSAL_AWAITING = exports.SAFE_PROPOSAL_UNCONFIRMED = exports.SAFE_EXEC_ABI = exports.SAFE_TX_TYPES = exports.SAFE_NONCE_GUIDANCE = exports.SAFE_SERVICE_PREFIX = exports.SAFE_PREFIX = void 0;
|
|
4
4
|
exports.safeServiceBase = safeServiceBase;
|
|
5
5
|
exports.swapDeadline = swapDeadline;
|
|
6
6
|
exports.safeQueueUrl = safeQueueUrl;
|
|
@@ -11,6 +11,18 @@ exports.safeTransactionHash = safeTransactionHash;
|
|
|
11
11
|
exports.canonicalSafeTxHash = canonicalSafeTxHash;
|
|
12
12
|
exports.safeExecutionResult = safeExecutionResult;
|
|
13
13
|
exports.requireSafeExecutionSuccess = requireSafeExecutionSuccess;
|
|
14
|
+
exports.safeTransactionRunsCalls = safeTransactionRunsCalls;
|
|
15
|
+
exports.safeExecutionRunsCalls = safeExecutionRunsCalls;
|
|
16
|
+
exports.readSafeAppExecution = readSafeAppExecution;
|
|
17
|
+
exports.requireSafeProposalSuccess = requireSafeProposalSuccess;
|
|
18
|
+
exports.heldCall = heldCall;
|
|
19
|
+
exports.stampedDeadline = stampedDeadline;
|
|
20
|
+
exports.findPendingSafeAppProposal = findPendingSafeAppProposal;
|
|
21
|
+
exports.lookAtSafeProposal = lookAtSafeProposal;
|
|
22
|
+
exports.watchSafeProposal = watchSafeProposal;
|
|
23
|
+
exports.atOnceExecution = atOnceExecution;
|
|
24
|
+
exports.chainAnswer = chainAnswer;
|
|
25
|
+
exports.reportedSafeExecution = reportedSafeExecution;
|
|
14
26
|
exports.usableSafeConfirmations = usableSafeConfirmations;
|
|
15
27
|
exports.safeExecutionSignatures = safeExecutionSignatures;
|
|
16
28
|
exports.safeExecutionArgs = safeExecutionArgs;
|
|
@@ -560,6 +572,318 @@ function requireSafeExecutionSuccess(receipt, safe, hash) {
|
|
|
560
572
|
}
|
|
561
573
|
throw new Error(result.reason);
|
|
562
574
|
}
|
|
575
|
+
/** What a Safe app flow says when it cannot confirm its proposal ran. */
|
|
576
|
+
exports.SAFE_PROPOSAL_UNCONFIRMED = "Safe proposal submitted, but confirmation is unavailable. Check Safe before taking another action.";
|
|
577
|
+
/** What a Safe app flow says while its proposal waits for the Safe's other signers. */
|
|
578
|
+
exports.SAFE_PROPOSAL_AWAITING = "Proposed to your Safe. Its other signers can approve it there.";
|
|
579
|
+
/**
|
|
580
|
+
* Whether the Safe transaction runs exactly the reviewed calls: one CALL,
|
|
581
|
+
* or, when `batch` permits it, a zero-value MultiSendCallOnly DELEGATECALL
|
|
582
|
+
* running every call in order. Persisted decimal values compare in wei.
|
|
583
|
+
*/
|
|
584
|
+
function safeTransactionRunsCalls(tx, calls, batch = true) {
|
|
585
|
+
if (calls.length === 1 && tx.operation === 0 && sameCall(calls[0], tx))
|
|
586
|
+
return true;
|
|
587
|
+
if (!batch || tx.value !== 0n)
|
|
588
|
+
return false;
|
|
589
|
+
const inner = (0, safe_js_1.multiSendCallsOf)(tx);
|
|
590
|
+
return (!!inner &&
|
|
591
|
+
inner.length === calls.length &&
|
|
592
|
+
inner.every((call, index) => sameCall(calls[index], call)));
|
|
593
|
+
}
|
|
594
|
+
/** Whether a transaction calls `safe`'s execTransaction of exactly the reviewed calls. */
|
|
595
|
+
function safeExecutionRunsCalls(transaction, safe, calls, batch = true) {
|
|
596
|
+
if (!transaction.to ||
|
|
597
|
+
!transaction.input ||
|
|
598
|
+
!(0, viem_1.isAddressEqual)(transaction.to, safe))
|
|
599
|
+
return false;
|
|
600
|
+
let decoded;
|
|
601
|
+
try {
|
|
602
|
+
decoded = (0, viem_1.decodeFunctionData)({
|
|
603
|
+
abi: exports.SAFE_EXEC_ABI,
|
|
604
|
+
data: transaction.input,
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
catch {
|
|
608
|
+
return false;
|
|
609
|
+
}
|
|
610
|
+
if (decoded.functionName !== "execTransaction")
|
|
611
|
+
return false;
|
|
612
|
+
const [to, value, data, operation] = decoded.args;
|
|
613
|
+
return safeTransactionRunsCalls({ to, value, data, operation }, calls, batch);
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* What the execution's receipt proves about the proposal a Safe app returned
|
|
617
|
+
* ({@link safeExecutionResult}). When Safe{Wallet} executed it at once, the
|
|
618
|
+
* reply is the execution's own hash and the SDK takes the Safe's one
|
|
619
|
+
* execution event in that receipt whatever its safeTxHash, so the execution
|
|
620
|
+
* must also be the Safe's execTransaction of exactly the reviewed calls, or
|
|
621
|
+
* the result is unproven.
|
|
622
|
+
*/
|
|
623
|
+
async function readSafeAppExecution({ client, receipt, safe, proposalHash, calls, batch = true, }) {
|
|
624
|
+
const result = safeExecutionResult(receipt, safe, proposalHash);
|
|
625
|
+
const atOnce = typeof receipt.transactionHash === "string" &&
|
|
626
|
+
receipt.transactionHash.toLowerCase() === proposalHash.toLowerCase();
|
|
627
|
+
if (!atOnce || (result.status !== "success" && result.status !== "failed")) {
|
|
628
|
+
return result;
|
|
629
|
+
}
|
|
630
|
+
const transaction = await client
|
|
631
|
+
.getTransaction({ hash: proposalHash })
|
|
632
|
+
.catch(() => null);
|
|
633
|
+
return transaction && safeExecutionRunsCalls(transaction, safe, calls, batch)
|
|
634
|
+
? result
|
|
635
|
+
: {
|
|
636
|
+
status: "unproven",
|
|
637
|
+
reason: `Transaction ${proposalHash} is not Safe ${safe}'s execution of the reviewed call.`,
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Throws unless the execution proves the Safe ran the reviewed proposal and
|
|
642
|
+
* its call succeeded ({@link readSafeAppExecution}): `failure` when the Safe
|
|
643
|
+
* ran it and it failed, and SAFE_PROPOSAL_UNCONFIRMED when it does not show
|
|
644
|
+
* this proposal ran.
|
|
645
|
+
*/
|
|
646
|
+
async function requireSafeProposalSuccess(execution, failure) {
|
|
647
|
+
const { status } = await readSafeAppExecution(execution);
|
|
648
|
+
if (status === "unproven")
|
|
649
|
+
throw new Error(exports.SAFE_PROPOSAL_UNCONFIRMED);
|
|
650
|
+
if (status !== "success")
|
|
651
|
+
throw new Error(failure);
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* The calls this app stamps with a field at send time, by selector: the
|
|
655
|
+
* stamp's argument, and whether the contract refuses the call once the chain
|
|
656
|
+
* passes it. Universal Router's `execute` and PositionManager's
|
|
657
|
+
* `modifyLiquidities` check a deadline; the expiration Permit2's `approve`
|
|
658
|
+
* sets only bounds the allowance it grants.
|
|
659
|
+
*/
|
|
660
|
+
const STAMPED_CALLS = {
|
|
661
|
+
// execute(bytes commands, bytes[] inputs, uint256 deadline)
|
|
662
|
+
"0x3593564c": {
|
|
663
|
+
params: [{ type: "bytes" }, { type: "bytes[]" }, { type: "uint256" }],
|
|
664
|
+
stamp: 2,
|
|
665
|
+
reverts: true,
|
|
666
|
+
},
|
|
667
|
+
// modifyLiquidities(bytes unlockData, uint256 deadline)
|
|
668
|
+
"0xdd46508f": {
|
|
669
|
+
params: [{ type: "bytes" }, { type: "uint256" }],
|
|
670
|
+
stamp: 1,
|
|
671
|
+
reverts: true,
|
|
672
|
+
},
|
|
673
|
+
// approve(address token, address spender, uint160 amount, uint48 expiration)
|
|
674
|
+
"0x87517c45": {
|
|
675
|
+
params: [
|
|
676
|
+
{ type: "address" },
|
|
677
|
+
{ type: "address" },
|
|
678
|
+
{ type: "uint160" },
|
|
679
|
+
{ type: "uint48" },
|
|
680
|
+
],
|
|
681
|
+
stamp: 3,
|
|
682
|
+
reverts: false,
|
|
683
|
+
},
|
|
684
|
+
};
|
|
685
|
+
/** A stamped call's shape and arguments, when its data is exactly their ABI encoding. */
|
|
686
|
+
function stampedArgs(call) {
|
|
687
|
+
const shape = STAMPED_CALLS[call.data.slice(0, 10).toLowerCase()];
|
|
688
|
+
if (!shape)
|
|
689
|
+
return null;
|
|
690
|
+
const encoded = `0x${call.data.slice(10)}`;
|
|
691
|
+
try {
|
|
692
|
+
const args = (0, viem_1.decodeAbiParameters)(shape.params, encoded);
|
|
693
|
+
// Any other encoding of the same arguments is held exactly as sent.
|
|
694
|
+
return (0, viem_1.encodeAbiParameters)(shape.params, args).toLowerCase() ===
|
|
695
|
+
encoded.toLowerCase()
|
|
696
|
+
? { shape, args }
|
|
697
|
+
: null;
|
|
698
|
+
}
|
|
699
|
+
catch {
|
|
700
|
+
return null;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* The call a Safe proposal of `call` holds: `call` with the field it is
|
|
705
|
+
* stamped with at send time zeroed, so the same action sent again with a later
|
|
706
|
+
* stamp is the action the proposal already holds. Any other call is held
|
|
707
|
+
* exactly as sent.
|
|
708
|
+
*/
|
|
709
|
+
function heldCall(call) {
|
|
710
|
+
const stamped = stampedArgs(call);
|
|
711
|
+
if (!stamped)
|
|
712
|
+
return call;
|
|
713
|
+
const args = [...stamped.args];
|
|
714
|
+
args[stamped.shape.stamp] = 0n;
|
|
715
|
+
return {
|
|
716
|
+
...call,
|
|
717
|
+
data: `${call.data.slice(0, 10)}${(0, viem_1.encodeAbiParameters)(stamped.shape.params, args).slice(2)}`,
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
/** The deadline after which the contract refuses `call`, or null for a call without one. */
|
|
721
|
+
function stampedDeadline(call) {
|
|
722
|
+
const stamped = stampedArgs(call);
|
|
723
|
+
return stamped?.shape.reverts
|
|
724
|
+
? BigInt(stamped.args[stamped.shape.stamp])
|
|
725
|
+
: null;
|
|
726
|
+
}
|
|
727
|
+
function sameCall(a, b) {
|
|
728
|
+
return ((0, viem_1.isAddressEqual)(a.to, b.to) &&
|
|
729
|
+
BigInt(a.value ?? 0n) === BigInt(b.value ?? 0n) &&
|
|
730
|
+
a.data.toLowerCase() === b.data.toLowerCase());
|
|
731
|
+
}
|
|
732
|
+
/** A Safe app proposal's one call, or null for any other Safe transaction. */
|
|
733
|
+
function proposedCall(tx) {
|
|
734
|
+
// Both callers have authenticated the record through the service reader.
|
|
735
|
+
const { to, data, value } = safeTransactionMessage(tx);
|
|
736
|
+
// A zero-refund CALL, as a Safe app proposes it.
|
|
737
|
+
return safeTransactionMatchesCall(tx, { to, data, value })
|
|
738
|
+
? { to, data, value }
|
|
739
|
+
: null;
|
|
740
|
+
}
|
|
741
|
+
/**
|
|
742
|
+
* A pending proposal of the action `call` makes in `safe`'s queue (its
|
|
743
|
+
* service record, its safeTxHash and the call it runs), read from Safe's
|
|
744
|
+
* service from the Safe's nonce in the latest block, or null: a Safe app
|
|
745
|
+
* never proposes an action that is already queued, whoever queued it,
|
|
746
|
+
* whatever its stamp ({@link heldCall}). A queued call the contract refuses
|
|
747
|
+
* once its deadline passed is passed over when that block is past the
|
|
748
|
+
* deadline: it can no longer run. Throws when the block, the nonce or the
|
|
749
|
+
* queue can't be read.
|
|
750
|
+
*/
|
|
751
|
+
async function findPendingSafeAppProposal(client, chainId, safe, call, service) {
|
|
752
|
+
// One block's view: its time, and the Safe's nonce in it. A proposal listed
|
|
753
|
+
// from that nonce had not run by that block, so a deadline already past then
|
|
754
|
+
// proves it never will.
|
|
755
|
+
const block = await client.getBlock();
|
|
756
|
+
const nonce = await (0, safe_js_1.readBoundedSafeNonce)(client, safe, {
|
|
757
|
+
blockNumber: block.number ?? undefined,
|
|
758
|
+
}).catch(() => null);
|
|
759
|
+
if (nonce === null || nonce > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
760
|
+
throw new Error("Could not read the Safe nonce.");
|
|
761
|
+
}
|
|
762
|
+
const held = heldCall(call);
|
|
763
|
+
const queued = (await listPendingSafeTransactions(chainId, safe, Number(nonce), service)).flatMap((tx) => {
|
|
764
|
+
const proposed = proposedCall(tx);
|
|
765
|
+
return proposed && sameCall(heldCall(proposed), held)
|
|
766
|
+
? [{ tx, call: proposed, deadline: stampedDeadline(proposed) }]
|
|
767
|
+
: [];
|
|
768
|
+
});
|
|
769
|
+
const live = queued.find(({ deadline }) => deadline === null || deadline >= block.timestamp);
|
|
770
|
+
return live
|
|
771
|
+
? {
|
|
772
|
+
tx: live.tx,
|
|
773
|
+
proposalHash: canonicalSafeTxHash(chainId, safe, live.tx),
|
|
774
|
+
call: live.call,
|
|
775
|
+
}
|
|
776
|
+
: null;
|
|
777
|
+
}
|
|
778
|
+
/**
|
|
779
|
+
* One look at `safe`'s proposal `proposalHash`: the latest block, the Safe's
|
|
780
|
+
* nonce in that block, and Safe's authenticated record of the proposal. A read
|
|
781
|
+
* that fails makes the look live.
|
|
782
|
+
*/
|
|
783
|
+
async function lookAtSafeProposal(client, chainId, safe, proposalHash, service) {
|
|
784
|
+
try {
|
|
785
|
+
const block = await client.getBlock();
|
|
786
|
+
const nonce = await (0, safe_js_1.readBoundedSafeNonce)(client, safe, {
|
|
787
|
+
blockNumber: block.number ?? undefined,
|
|
788
|
+
});
|
|
789
|
+
const record = await readSafeTransaction(chainId, safe, proposalHash, service);
|
|
790
|
+
if (nonce === null || record.isExecuted)
|
|
791
|
+
return "live";
|
|
792
|
+
if (nonce > safeTransactionMessage(record).nonce)
|
|
793
|
+
return "passed";
|
|
794
|
+
const call = proposedCall(record);
|
|
795
|
+
const deadline = call && stampedDeadline(call);
|
|
796
|
+
return deadline !== null && block.timestamp > deadline ? "expired" : "live";
|
|
797
|
+
}
|
|
798
|
+
catch {
|
|
799
|
+
return "live";
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
/** A watch looks at its proposal once a minute, so it reads the Safe's nonce at most that often. */
|
|
803
|
+
const SAFE_LOOK_MS = 60_000;
|
|
804
|
+
/** How long looks in a row must find the Safe past a proposal before it counts as replaced. */
|
|
805
|
+
const SAFE_REPLACED_AFTER_MS = 10 * 60_000;
|
|
806
|
+
/**
|
|
807
|
+
* Watches a proposal awaiting its signers, one {@link lookAtSafeProposal} a
|
|
808
|
+
* minute, until `signal` aborts. It ends `expired` at the first look that
|
|
809
|
+
* finds it expired, and `replaced` once looks in a row have found it passed
|
|
810
|
+
* for ten minutes: one such look proves nothing, since Safe's service may list
|
|
811
|
+
* the proposal's own execution later. Any other look starts that count again.
|
|
812
|
+
*/
|
|
813
|
+
async function watchSafeProposal(client, chainId, safe, proposalHash, signal, service) {
|
|
814
|
+
let passedSince = null;
|
|
815
|
+
for (;;) {
|
|
816
|
+
await (0, pause_js_1.pause)(SAFE_LOOK_MS, signal, waitAborted);
|
|
817
|
+
const look = await lookAtSafeProposal(client, chainId, safe, proposalHash, service);
|
|
818
|
+
if (look === "expired")
|
|
819
|
+
return look;
|
|
820
|
+
passedSince = look === "passed" ? (passedSince ?? Date.now()) : null;
|
|
821
|
+
if (passedSince !== null &&
|
|
822
|
+
Date.now() - passedSince >= SAFE_REPLACED_AFTER_MS)
|
|
823
|
+
return "replaced";
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
/** Looks at the chain for an execution returned at once, and the pause between them. */
|
|
827
|
+
const AT_ONCE_LOOKS = 5;
|
|
828
|
+
const AT_ONCE_LOOK_MS = 2_000;
|
|
829
|
+
/**
|
|
830
|
+
* The transaction `hash` names on the chain, or null: Safe{Wallet} replies
|
|
831
|
+
* with the execution's own hash when the owner executes at once, and the node
|
|
832
|
+
* may learn it a moment later. It looks up to 5 times, 2 seconds apart (8
|
|
833
|
+
* seconds at most), before the reply counts as a proposal.
|
|
834
|
+
*/
|
|
835
|
+
async function atOnceExecution(client, hash) {
|
|
836
|
+
for (let look = 1; look <= AT_ONCE_LOOKS; look += 1) {
|
|
837
|
+
try {
|
|
838
|
+
return await client.getTransaction({ hash });
|
|
839
|
+
}
|
|
840
|
+
catch {
|
|
841
|
+
if (look < AT_ONCE_LOOKS) {
|
|
842
|
+
await (0, pause_js_1.pause)(AT_ONCE_LOOK_MS, undefined, waitAborted);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
return null;
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* The chain's last word before a proposal ends unproven: what `read` returns,
|
|
850
|
+
* or null when the chain says there is none (viem's transaction or receipt
|
|
851
|
+
* not-found). A node that can't answer says nothing, so it is asked again a
|
|
852
|
+
* minute later, for as long as it takes, with `onRetry` called first. With
|
|
853
|
+
* `exists`, the chain already proved the thing exists (its receipt is in
|
|
854
|
+
* hand), so a not-found only says the node is behind, and is asked again too.
|
|
855
|
+
*/
|
|
856
|
+
async function chainAnswer(read, { exists = false, onRetry } = {}) {
|
|
857
|
+
for (;;) {
|
|
858
|
+
try {
|
|
859
|
+
return await read();
|
|
860
|
+
}
|
|
861
|
+
catch (error) {
|
|
862
|
+
const notFound = error instanceof viem_1.TransactionNotFoundError ||
|
|
863
|
+
error instanceof viem_1.TransactionReceiptNotFoundError;
|
|
864
|
+
if (notFound && !exists)
|
|
865
|
+
return null;
|
|
866
|
+
}
|
|
867
|
+
onRetry?.();
|
|
868
|
+
await (0, pause_js_1.pause)(SAFE_LOOK_MS, undefined, waitAborted);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* The execution Safe's authenticated record names for `safeTxHash` when
|
|
873
|
+
* `error` is its service's report that the proposal ran and failed, or null.
|
|
874
|
+
* Only that execution's receipt decides the proposal, never the report alone.
|
|
875
|
+
*/
|
|
876
|
+
async function reportedSafeExecution(error, chainId, safe, safeTxHash, service) {
|
|
877
|
+
if (!(error instanceof Error) ||
|
|
878
|
+
!/executed the proposal.*failed/i.test(error.message))
|
|
879
|
+
return null;
|
|
880
|
+
const record = await readSafeTransaction(chainId, safe, safeTxHash, service).catch(() => null);
|
|
881
|
+
const hash = record
|
|
882
|
+
?.transactionHash;
|
|
883
|
+
return typeof hash === "string" && /^0x[0-9a-fA-F]{64}$/u.test(hash)
|
|
884
|
+
? hash
|
|
885
|
+
: null;
|
|
886
|
+
}
|
|
563
887
|
// ── Signatures ───────────────────────────────────────────────────────────────
|
|
564
888
|
/**
|
|
565
889
|
* One confirmation's part of Safe's `signatures` bytes, without 0x:
|