@panoptic-eng/sdk 1.0.71 → 1.0.73

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.
@@ -1,7 +1,6 @@
1
1
  import { StateViewAbi } from "./StateView-q4yMpBY6.js";
2
- import { PanopticError, getBlockMeta, getPool, getPoolMetadata, stateViewAbi, submitWrite, uniswapV3PoolAbi } from "./rates-DlqTkuXt.js";
3
- import { getLegLiquidityRange, tickToSqrtPriceX96 } from "./greeks-DNPP24KL.js";
4
- import { decodeAllLegs, decodeTokenId } from "./writes-DBu2ltcP.js";
2
+ import { PanopticError, decodeAllLegs, decodeTokenId, getBlockMeta, getPool, getPoolMetadata, stateViewAbi, submitWrite, uniswapV3PoolAbi } from "./rates-c9XVKm3m.js";
3
+ import { getLegLiquidityRange, tickToSqrtPriceX96 } from "./greeks-CEv-Uex1.js";
5
4
  import { BaseError, ContractFunctionRevertedError, ExecutionRevertedError, encodeAbiParameters, encodeFunctionData, encodePacked, erc20Abi, isAddressEqual, maxUint256, toHex, zeroAddress } from "viem";
6
5
  import Decimal from "decimal.js";
7
6
 
@@ -0,0 +1,166 @@
1
+ import { Address, Hex } from "viem";
2
+
3
+ //#region src/safe/signedSafeTx.d.ts
4
+ declare const safeAbi: readonly [{
5
+ readonly type: "event";
6
+ readonly name: "ExecutionSuccess";
7
+ readonly inputs: readonly [{
8
+ readonly name: "txHash";
9
+ readonly type: "bytes32";
10
+ readonly indexed: true;
11
+ }, {
12
+ readonly name: "payment";
13
+ readonly type: "uint256";
14
+ readonly indexed: false;
15
+ }];
16
+ }, {
17
+ readonly type: "function";
18
+ readonly name: "execTransaction";
19
+ readonly stateMutability: "payable";
20
+ readonly inputs: readonly [{
21
+ readonly name: "to";
22
+ readonly type: "address";
23
+ }, {
24
+ readonly name: "value";
25
+ readonly type: "uint256";
26
+ }, {
27
+ readonly name: "data";
28
+ readonly type: "bytes";
29
+ }, {
30
+ readonly name: "operation";
31
+ readonly type: "uint8";
32
+ }, {
33
+ readonly name: "safeTxGas";
34
+ readonly type: "uint256";
35
+ }, {
36
+ readonly name: "baseGas";
37
+ readonly type: "uint256";
38
+ }, {
39
+ readonly name: "gasPrice";
40
+ readonly type: "uint256";
41
+ }, {
42
+ readonly name: "gasToken";
43
+ readonly type: "address";
44
+ }, {
45
+ readonly name: "refundReceiver";
46
+ readonly type: "address";
47
+ }, {
48
+ readonly name: "signatures";
49
+ readonly type: "bytes";
50
+ }];
51
+ readonly outputs: readonly [{
52
+ readonly name: "success";
53
+ readonly type: "bool";
54
+ }];
55
+ }, {
56
+ readonly type: "function";
57
+ readonly name: "VERSION";
58
+ readonly stateMutability: "view";
59
+ readonly inputs: readonly [];
60
+ readonly outputs: readonly [{
61
+ readonly type: "string";
62
+ }];
63
+ }, {
64
+ readonly type: "function";
65
+ readonly name: "nonce";
66
+ readonly stateMutability: "view";
67
+ readonly inputs: readonly [];
68
+ readonly outputs: readonly [{
69
+ readonly type: "uint256";
70
+ }];
71
+ }, {
72
+ readonly type: "function";
73
+ readonly name: "getThreshold";
74
+ readonly stateMutability: "view";
75
+ readonly inputs: readonly [];
76
+ readonly outputs: readonly [{
77
+ readonly type: "uint256";
78
+ }];
79
+ }, {
80
+ readonly type: "function";
81
+ readonly name: "getOwners";
82
+ readonly stateMutability: "view";
83
+ readonly inputs: readonly [];
84
+ readonly outputs: readonly [{
85
+ readonly type: "address[]";
86
+ }];
87
+ }];
88
+ /** A plain call the owner asked their wallet to send from the Safe. */
89
+ interface SafeCall {
90
+ to: Address;
91
+ value: bigint;
92
+ data: Hex;
93
+ }
94
+ interface SafeTx extends SafeCall {
95
+ operation: 0 | 1;
96
+ safeTxGas: bigint;
97
+ baseGas: bigint;
98
+ gasPrice: bigint;
99
+ gasToken: Address;
100
+ refundReceiver: Address;
101
+ nonce: bigint;
102
+ }
103
+ interface SignedSafeTx {
104
+ safe: Address;
105
+ chainId: number;
106
+ tx: SafeTx;
107
+ safeTxHash: Hex;
108
+ signer: Address;
109
+ /** Packed `signatures` argument for `execTransaction`. */
110
+ signatures: Hex;
111
+ }
112
+ type SignedSafeTxErrorCode = 'INVALID_SIGNATURE' | 'THRESHOLD_NOT_MET' | 'SIGNATURE_MISMATCH';
113
+ declare class SignedSafeTxError extends Error {
114
+ readonly code: SignedSafeTxErrorCode;
115
+ constructor(code: SignedSafeTxErrorCode, message: string);
116
+ }
117
+ /** EIP-712 SafeTx hash (Safe ≥ 1.3 domain: chainId + verifyingContract). */
118
+ declare function hashSafeTx(params: {
119
+ chainId: number;
120
+ safe: Address;
121
+ tx: SafeTx;
122
+ }): Hex;
123
+ /**
124
+ * A wallet signing a plain call for a Safe owner (Rabby, Safe{Wallet}) signs it
125
+ * with no refund or gas fields; only the nonce varies.
126
+ */
127
+ declare function safeTxForCall(call: SafeCall, nonce: bigint): SafeTx;
128
+ /** True for a 65-byte ECDSA signature — what a Safe-owner wallet returns instead of a tx hash. */
129
+ declare function isSafeOwnerSignature(value: unknown): value is Hex;
130
+ /**
131
+ * Rejects anything that cannot be a Safe owner's ECDSA signature, without any
132
+ * RPC: 65 bytes, supported v (raw 0/1/27/28 or `eth_sign` 31/32), and r, s in
133
+ * the curve range.
134
+ */
135
+ declare function assertSafeOwnerSignature(signature: Hex): void;
136
+ /**
137
+ * Recovers the signer of `safeTxHash`, accepting raw ECDSA (v 27/28, or 0/1)
138
+ * and `eth_sign` (v 31/32) signatures, and returns the signature in the form
139
+ * the Safe verifies.
140
+ */
141
+ declare function recoverSafeTxSigner(safeTxHash: Hex, signature: Hex): Promise<{
142
+ signer: Address;
143
+ signature: Hex;
144
+ }>;
145
+ /**
146
+ * Resolves an owner's signature over a plain call into an executable SafeTx,
147
+ * given the Safe's on-chain `nonce`, `owners` and `threshold`. The signed nonce
148
+ * is not part of the call, so it is searched from the on-chain nonce forward
149
+ * (wallets may sign ahead of queued transactions).
150
+ */
151
+ declare function resolveSignedSafeTx(params: {
152
+ chainId: number;
153
+ safe: Address;
154
+ call: SafeCall;
155
+ signature: Hex;
156
+ state: {
157
+ nonce: bigint;
158
+ threshold: bigint;
159
+ owners: readonly Address[];
160
+ };
161
+ nonceWindow?: number;
162
+ }): Promise<SignedSafeTx>;
163
+ /** `execTransaction` arguments for a resolved signed SafeTx. */
164
+ declare function execTransactionArgs(signed: SignedSafeTx): readonly [Address, bigint, `0x${string}`, 0 | 1, bigint, bigint, bigint, Address, Address, `0x${string}`]; //#endregion
165
+ export { SafeCall, SafeTx, SignedSafeTx, SignedSafeTxError, SignedSafeTxErrorCode, assertSafeOwnerSignature, execTransactionArgs, hashSafeTx, isSafeOwnerSignature, recoverSafeTxSigner, resolveSignedSafeTx, safeAbi, safeTxForCall };
166
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":["Address","Hex","safeAbi","SafeCall","SafeTx","SignedSafeTx","SignedSafeTxErrorCode","SignedSafeTxError","Error","hashSafeTx","safeTxForCall","isSafeOwnerSignature","assertSafeOwnerSignature","recoverSafeTxSigner","Promise","resolveSignedSafeTx","execTransactionArgs"],"sources":["../../src/safe/signedSafeTx.d.ts"],"sourcesContent":null,"mappings":";;;cACqBE;;EAAAA,SAAAA,IAmFnB,EAAA,kBAAA;;IAEeC,SAAQ,IAAA,EAAA,QAAA;IAAA,SAAA,IAAA,EAAA,SAAA;IACjBH,SAAAA,OAAAA,EAAAA,IAAAA;EAAO,CAAA,EAELC;IAAG,SAAA,IAAA,EAAA,SAAA;IAEIG,SAAM,IAAA,EAAA,SAAA;IAAA,SAAA,OAAA,EAAA,KAAA;EAAA,CAAA,CAAA;CAKF,EAAA;EACM,SANKD,IAAAA,EAAAA,UAAAA;EAAQ,SAAA,IAAA,EAAA,iBAAA;EASvBE,SAAAA,eAAY,EAAA,SAAA;EAAA,SAAA,MAAA,EAAA,SAAA,CAAA;IACnBL,SAAAA,IAAAA,EAAAA,IAAAA;IAEFI,SAAAA,IAAAA,EAAAA,SAAAA;EAAM,CAAA,EACEH;IACJD,SAAAA,IAAAA,EAAAA,OAAAA;IAEIC,SAAAA,IAAAA,EAAAA,SAAAA;EAAG,CAAA,EAAA;IAEPK,SAAAA,IAAAA,EAAAA,MAAqB;IACZC,SAAAA,IAAAA,EAAAA,OAAiB;EAAA,CAAA,EAAA;IACnBD,SAAAA,IAAAA,EAAAA,WAAAA;IACGA,SAAAA,IAAAA,EAAAA,OAAAA;EAAqB,CAAA,EAFIE;IAAK,SAAA,IAAA,EAAA,WAAA;;EAK5BC,CAAAA,EAAAA;IAAU,SAAA,IAAA,EAAA,SAAA;IAExBT,SAAAA,IAAAA,EAAAA,SAAAA;EAAO,CAAA,EACTI;IACJH,SAAAA,IAAAA,EAAAA,UAAAA;IAAG,SAAA,IAAA,EAAA,SAAA;;;;;IAKiBS,SAAAA,IAAa,EAAA,gBAAA;IAAA,SAAA,IAAA,EAAA,SAAA;EAAA,CAAA,EAAOP;IAA0BC,SAAAA,IAAAA,EAAAA,YAAAA;IAAM,SAAA,IAAA,EAAA,OAAA;;EAEpDO,SAAAA,OAAAA,EAAAA,SAAoB,CAAA;;;;;;EAMpBC,SAAAA,IAAAA,EAAAA,SAAAA;;;;;;AAMxB,CAAA,EAAA;EAA2C,SAAA,IAAA,EAAA,UAAA;EAAA,SAAaX,IAAAA,EAAAA,OAAAA;EAAG,SAAaA,eAAAA,EAAAA,MAAAA;EAAG,SAC/DD,MAAAA,EAAAA,SAAAA,EAAAA;EAAO,SACJC,OAAAA,EAAAA,SAAAA,CAAAA;IAF+Da,SAAAA,IAAAA,EAAAA,SAAAA;EAAO,CAAA,CAAA;;;;;;;IAU7DC,SAAAA,IAAAA,EAAAA,SAAmB;EAAA,CAAA,CAAA;CAAA,EAAA;EAE1B,SACPZ,IAAAA,EAAAA,UAAAA;EAAQ,SACHF,IAAAA,EAAAA,WAAAA;EAAG,SAIOD,eAAAA,EAAAA,MAAAA;EAAO,SAGpBK,MAAAA,EAAAA,SAAAA,EAAAA;EAAY,SAApBS,OAAAA,EAAAA,SAAAA,CAAAA;IAAO,SAAA,IAAA,EAAA,WAAA;;AAEX,CAAA,CAAA;;AAAoDT,UA3EnCF,QAAAA,CA2EmCE;EAAY,EAAA,EA1ExDL,OA0EqEA;EAAO,KAAwDA,EAAAA,MAAAA;EAAO,IAAEA,EAxE3IC,GAwE2ID;AAAO;UAtE3II,MAAAA,SAAeD;;;;;YAKlBH;kBACMA;;;UAGHK,YAAAA;QACPL;;MAEFI;cACQH;UACJD;;cAEIC;;KAEJK,qBAAAA;cACSC,iBAAAA,SAA0BC,KAAAA;iBAC5BF;oBACGA;;;iBAGEG,UAAAA;;QAEdT;MACFI;IACJH;;;;;iBAKoBS,aAAAA,OAAoBP,0BAA0BC;;iBAE9CO,oBAAAA,2BAA+CV;;;;;;iBAM/CW,wBAAAA,YAAoCX;;;;;;iBAMpCY,mBAAAA,aAAgCZ,gBAAgBA,MAAMa;UAClEd;aACGC;;;;;;;;iBAQSc,mBAAAA;;QAEdf;QACAG;aACKF;;;;qBAIUD;;;IAGrBc,QAAQT;;iBAEYW,mBAAAA,SAA4BX,yBAAyBL,+DAA+DA,SAASA"}
@@ -0,0 +1,278 @@
1
+ import { concatHex, getAddress, hashMessage, hashTypedData, hexToBigInt, hexToNumber, isAddressEqual, numberToHex, recoverAddress, sliceHex, zeroAddress } from "viem";
2
+
3
+ //#region src/safe/signedSafeTx.ts
4
+ const safeAbi = [
5
+ {
6
+ type: "event",
7
+ name: "ExecutionSuccess",
8
+ inputs: [{
9
+ name: "txHash",
10
+ type: "bytes32",
11
+ indexed: true
12
+ }, {
13
+ name: "payment",
14
+ type: "uint256",
15
+ indexed: false
16
+ }]
17
+ },
18
+ {
19
+ type: "function",
20
+ name: "execTransaction",
21
+ stateMutability: "payable",
22
+ inputs: [
23
+ {
24
+ name: "to",
25
+ type: "address"
26
+ },
27
+ {
28
+ name: "value",
29
+ type: "uint256"
30
+ },
31
+ {
32
+ name: "data",
33
+ type: "bytes"
34
+ },
35
+ {
36
+ name: "operation",
37
+ type: "uint8"
38
+ },
39
+ {
40
+ name: "safeTxGas",
41
+ type: "uint256"
42
+ },
43
+ {
44
+ name: "baseGas",
45
+ type: "uint256"
46
+ },
47
+ {
48
+ name: "gasPrice",
49
+ type: "uint256"
50
+ },
51
+ {
52
+ name: "gasToken",
53
+ type: "address"
54
+ },
55
+ {
56
+ name: "refundReceiver",
57
+ type: "address"
58
+ },
59
+ {
60
+ name: "signatures",
61
+ type: "bytes"
62
+ }
63
+ ],
64
+ outputs: [{
65
+ name: "success",
66
+ type: "bool"
67
+ }]
68
+ },
69
+ {
70
+ type: "function",
71
+ name: "VERSION",
72
+ stateMutability: "view",
73
+ inputs: [],
74
+ outputs: [{ type: "string" }]
75
+ },
76
+ {
77
+ type: "function",
78
+ name: "nonce",
79
+ stateMutability: "view",
80
+ inputs: [],
81
+ outputs: [{ type: "uint256" }]
82
+ },
83
+ {
84
+ type: "function",
85
+ name: "getThreshold",
86
+ stateMutability: "view",
87
+ inputs: [],
88
+ outputs: [{ type: "uint256" }]
89
+ },
90
+ {
91
+ type: "function",
92
+ name: "getOwners",
93
+ stateMutability: "view",
94
+ inputs: [],
95
+ outputs: [{ type: "address[]" }]
96
+ }
97
+ ];
98
+ var SignedSafeTxError = class extends Error {
99
+ constructor(code, message) {
100
+ super(message);
101
+ this.code = code;
102
+ this.name = "SignedSafeTxError";
103
+ }
104
+ };
105
+ const SAFE_TX_TYPES = { SafeTx: [
106
+ {
107
+ name: "to",
108
+ type: "address"
109
+ },
110
+ {
111
+ name: "value",
112
+ type: "uint256"
113
+ },
114
+ {
115
+ name: "data",
116
+ type: "bytes"
117
+ },
118
+ {
119
+ name: "operation",
120
+ type: "uint8"
121
+ },
122
+ {
123
+ name: "safeTxGas",
124
+ type: "uint256"
125
+ },
126
+ {
127
+ name: "baseGas",
128
+ type: "uint256"
129
+ },
130
+ {
131
+ name: "gasPrice",
132
+ type: "uint256"
133
+ },
134
+ {
135
+ name: "gasToken",
136
+ type: "address"
137
+ },
138
+ {
139
+ name: "refundReceiver",
140
+ type: "address"
141
+ },
142
+ {
143
+ name: "nonce",
144
+ type: "uint256"
145
+ }
146
+ ] };
147
+ /** EIP-712 SafeTx hash (Safe ≥ 1.3 domain: chainId + verifyingContract). */
148
+ function hashSafeTx(params) {
149
+ return hashTypedData({
150
+ domain: {
151
+ chainId: params.chainId,
152
+ verifyingContract: params.safe
153
+ },
154
+ types: SAFE_TX_TYPES,
155
+ primaryType: "SafeTx",
156
+ message: params.tx
157
+ });
158
+ }
159
+ /**
160
+ * A wallet signing a plain call for a Safe owner (Rabby, Safe{Wallet}) signs it
161
+ * with no refund or gas fields; only the nonce varies.
162
+ */
163
+ function safeTxForCall(call, nonce) {
164
+ return {
165
+ ...call,
166
+ operation: 0,
167
+ safeTxGas: 0n,
168
+ baseGas: 0n,
169
+ gasPrice: 0n,
170
+ gasToken: zeroAddress,
171
+ refundReceiver: zeroAddress,
172
+ nonce
173
+ };
174
+ }
175
+ /** True for a 65-byte ECDSA signature — what a Safe-owner wallet returns instead of a tx hash. */
176
+ function isSafeOwnerSignature(value) {
177
+ return typeof value === "string" && /^0x[0-9a-fA-F]{130}$/.test(value);
178
+ }
179
+ const SECP256K1_N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n;
180
+ const SUPPORTED_V = new Set([
181
+ 0,
182
+ 1,
183
+ 27,
184
+ 28,
185
+ 31,
186
+ 32
187
+ ]);
188
+ /**
189
+ * Rejects anything that cannot be a Safe owner's ECDSA signature, without any
190
+ * RPC: 65 bytes, supported v (raw 0/1/27/28 or `eth_sign` 31/32), and r, s in
191
+ * the curve range.
192
+ */
193
+ function assertSafeOwnerSignature(signature) {
194
+ if (!isSafeOwnerSignature(signature)) throw new SignedSafeTxError("INVALID_SIGNATURE", "expected a 65-byte ECDSA signature");
195
+ const r = hexToBigInt(sliceHex(signature, 0, 32));
196
+ const s = hexToBigInt(sliceHex(signature, 32, 64));
197
+ const v = hexToNumber(sliceHex(signature, 64, 65));
198
+ if (!SUPPORTED_V.has(v)) throw new SignedSafeTxError("INVALID_SIGNATURE", `unsupported signature v=${v}`);
199
+ if (r === 0n || r >= SECP256K1_N || s === 0n || s >= SECP256K1_N) throw new SignedSafeTxError("INVALID_SIGNATURE", "signature r/s out of range");
200
+ }
201
+ /**
202
+ * Recovers the signer of `safeTxHash`, accepting raw ECDSA (v 27/28, or 0/1)
203
+ * and `eth_sign` (v 31/32) signatures, and returns the signature in the form
204
+ * the Safe verifies.
205
+ */
206
+ async function recoverSafeTxSigner(safeTxHash, signature) {
207
+ assertSafeOwnerSignature(signature);
208
+ const rs = sliceHex(signature, 0, 64);
209
+ const v = hexToNumber(sliceHex(signature, 64, 65));
210
+ const ethSign = v === 31 || v === 32;
211
+ const normalized = ethSign ? signature : concatHex([rs, numberToHex(v < 27 ? v + 27 : v, { size: 1 })]);
212
+ try {
213
+ const signer = ethSign ? await recoverAddress({
214
+ hash: hashMessage({ raw: safeTxHash }),
215
+ signature: concatHex([rs, numberToHex(v - 4, { size: 1 })])
216
+ }) : await recoverAddress({
217
+ hash: safeTxHash,
218
+ signature: normalized
219
+ });
220
+ return {
221
+ signer,
222
+ signature: normalized
223
+ };
224
+ } catch (error) {
225
+ const reason = error instanceof Error ? error.message : String(error);
226
+ throw new SignedSafeTxError("INVALID_SIGNATURE", `signature recovery failed: ${reason}`);
227
+ }
228
+ }
229
+ /**
230
+ * Resolves an owner's signature over a plain call into an executable SafeTx,
231
+ * given the Safe's on-chain `nonce`, `owners` and `threshold`. The signed nonce
232
+ * is not part of the call, so it is searched from the on-chain nonce forward
233
+ * (wallets may sign ahead of queued transactions).
234
+ */
235
+ async function resolveSignedSafeTx(params) {
236
+ const safe = getAddress(params.safe);
237
+ const nonceWindow = params.nonceWindow ?? 5;
238
+ const { nonce, threshold, owners } = params.state;
239
+ if (threshold !== 1n) throw new SignedSafeTxError("THRESHOLD_NOT_MET", `Safe threshold is ${threshold}; a single owner signature cannot execute`);
240
+ for (let offset = 0n; offset < BigInt(nonceWindow); offset++) {
241
+ const tx = safeTxForCall(params.call, nonce + offset);
242
+ const safeTxHash = hashSafeTx({
243
+ chainId: params.chainId,
244
+ safe,
245
+ tx
246
+ });
247
+ const { signer, signature } = await recoverSafeTxSigner(safeTxHash, params.signature);
248
+ if (owners.some((owner) => isAddressEqual(owner, signer))) return {
249
+ safe,
250
+ chainId: params.chainId,
251
+ tx,
252
+ safeTxHash,
253
+ signer,
254
+ signatures: signature
255
+ };
256
+ }
257
+ throw new SignedSafeTxError("SIGNATURE_MISMATCH", `signature does not recover to an owner of ${safe} for nonces ${nonce}..${nonce + BigInt(nonceWindow) - 1n}`);
258
+ }
259
+ /** `execTransaction` arguments for a resolved signed SafeTx. */
260
+ function execTransactionArgs(signed) {
261
+ const { tx } = signed;
262
+ return [
263
+ tx.to,
264
+ tx.value,
265
+ tx.data,
266
+ tx.operation,
267
+ tx.safeTxGas,
268
+ tx.baseGas,
269
+ tx.gasPrice,
270
+ tx.gasToken,
271
+ tx.refundReceiver,
272
+ signed.signatures
273
+ ];
274
+ }
275
+
276
+ //#endregion
277
+ export { SignedSafeTxError, assertSafeOwnerSignature, execTransactionArgs, hashSafeTx, isSafeOwnerSignature, recoverSafeTxSigner, resolveSignedSafeTx, safeAbi, safeTxForCall };
278
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["code: SignedSafeTxErrorCode","message: string","params: { chainId: number; safe: Address; tx: SafeTx }","call: SafeCall","nonce: bigint","value: unknown","signature: Hex","safeTxHash: Hex","params: {\n chainId: number\n safe: Address\n call: SafeCall\n signature: Hex\n state: { nonce: bigint; threshold: bigint; owners: readonly Address[] }\n nonceWindow?: number\n}","signed: SignedSafeTx"],"sources":["../../src/safe/signedSafeTx.ts"],"sourcesContent":["import {\n type Address,\n type Hex,\n concatHex,\n getAddress,\n hashMessage,\n hashTypedData,\n hexToBigInt,\n hexToNumber,\n isAddressEqual,\n numberToHex,\n recoverAddress,\n sliceHex,\n zeroAddress,\n} from 'viem'\n\nexport const safeAbi = [\n {\n type: 'event',\n name: 'ExecutionSuccess',\n inputs: [\n { name: 'txHash', type: 'bytes32', indexed: true },\n { name: 'payment', type: 'uint256', indexed: false },\n ],\n },\n {\n type: 'function',\n name: 'execTransaction',\n stateMutability: 'payable',\n inputs: [\n { name: 'to', type: 'address' },\n { name: 'value', type: 'uint256' },\n { name: 'data', type: 'bytes' },\n { name: 'operation', type: 'uint8' },\n { name: 'safeTxGas', type: 'uint256' },\n { name: 'baseGas', type: 'uint256' },\n { name: 'gasPrice', type: 'uint256' },\n { name: 'gasToken', type: 'address' },\n { name: 'refundReceiver', type: 'address' },\n { name: 'signatures', type: 'bytes' },\n ],\n outputs: [{ name: 'success', type: 'bool' }],\n },\n {\n type: 'function',\n name: 'VERSION',\n stateMutability: 'view',\n inputs: [],\n outputs: [{ type: 'string' }],\n },\n {\n type: 'function',\n name: 'nonce',\n stateMutability: 'view',\n inputs: [],\n outputs: [{ type: 'uint256' }],\n },\n {\n type: 'function',\n name: 'getThreshold',\n stateMutability: 'view',\n inputs: [],\n outputs: [{ type: 'uint256' }],\n },\n {\n type: 'function',\n name: 'getOwners',\n stateMutability: 'view',\n inputs: [],\n outputs: [{ type: 'address[]' }],\n },\n] as const\n\n/** A plain call the owner asked their wallet to send from the Safe. */\nexport interface SafeCall {\n to: Address\n value: bigint\n data: Hex\n}\n\nexport interface SafeTx extends SafeCall {\n operation: 0 | 1\n safeTxGas: bigint\n baseGas: bigint\n gasPrice: bigint\n gasToken: Address\n refundReceiver: Address\n nonce: bigint\n}\n\nexport interface SignedSafeTx {\n safe: Address\n chainId: number\n tx: SafeTx\n safeTxHash: Hex\n signer: Address\n /** Packed `signatures` argument for `execTransaction`. */\n signatures: Hex\n}\n\nexport type SignedSafeTxErrorCode = 'INVALID_SIGNATURE' | 'THRESHOLD_NOT_MET' | 'SIGNATURE_MISMATCH'\n\nexport class SignedSafeTxError extends Error {\n constructor(\n readonly code: SignedSafeTxErrorCode,\n message: string,\n ) {\n super(message)\n this.name = 'SignedSafeTxError'\n }\n}\n\nconst SAFE_TX_TYPES = {\n SafeTx: [\n { name: 'to', type: 'address' },\n { name: 'value', type: 'uint256' },\n { name: 'data', type: 'bytes' },\n { name: 'operation', type: 'uint8' },\n { name: 'safeTxGas', type: 'uint256' },\n { name: 'baseGas', type: 'uint256' },\n { name: 'gasPrice', type: 'uint256' },\n { name: 'gasToken', type: 'address' },\n { name: 'refundReceiver', type: 'address' },\n { name: 'nonce', type: 'uint256' },\n ],\n} as const\n\n/** EIP-712 SafeTx hash (Safe ≥ 1.3 domain: chainId + verifyingContract). */\nexport function hashSafeTx(params: { chainId: number; safe: Address; tx: SafeTx }): Hex {\n return hashTypedData({\n domain: { chainId: params.chainId, verifyingContract: params.safe },\n types: SAFE_TX_TYPES,\n primaryType: 'SafeTx',\n message: params.tx,\n })\n}\n\n/**\n * A wallet signing a plain call for a Safe owner (Rabby, Safe{Wallet}) signs it\n * with no refund or gas fields; only the nonce varies.\n */\nexport function safeTxForCall(call: SafeCall, nonce: bigint): SafeTx {\n return {\n ...call,\n operation: 0,\n safeTxGas: 0n,\n baseGas: 0n,\n gasPrice: 0n,\n gasToken: zeroAddress,\n refundReceiver: zeroAddress,\n nonce,\n }\n}\n\n/** True for a 65-byte ECDSA signature — what a Safe-owner wallet returns instead of a tx hash. */\nexport function isSafeOwnerSignature(value: unknown): value is Hex {\n return typeof value === 'string' && /^0x[0-9a-fA-F]{130}$/.test(value)\n}\n\nconst SECP256K1_N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n\nconst SUPPORTED_V = new Set([0, 1, 27, 28, 31, 32])\n\n/**\n * Rejects anything that cannot be a Safe owner's ECDSA signature, without any\n * RPC: 65 bytes, supported v (raw 0/1/27/28 or `eth_sign` 31/32), and r, s in\n * the curve range.\n */\nexport function assertSafeOwnerSignature(signature: Hex): void {\n if (!isSafeOwnerSignature(signature)) {\n throw new SignedSafeTxError('INVALID_SIGNATURE', 'expected a 65-byte ECDSA signature')\n }\n const r = hexToBigInt(sliceHex(signature, 0, 32))\n const s = hexToBigInt(sliceHex(signature, 32, 64))\n const v = hexToNumber(sliceHex(signature, 64, 65))\n if (!SUPPORTED_V.has(v)) {\n throw new SignedSafeTxError('INVALID_SIGNATURE', `unsupported signature v=${v}`)\n }\n if (r === 0n || r >= SECP256K1_N || s === 0n || s >= SECP256K1_N) {\n throw new SignedSafeTxError('INVALID_SIGNATURE', 'signature r/s out of range')\n }\n}\n\n/**\n * Recovers the signer of `safeTxHash`, accepting raw ECDSA (v 27/28, or 0/1)\n * and `eth_sign` (v 31/32) signatures, and returns the signature in the form\n * the Safe verifies.\n */\nexport async function recoverSafeTxSigner(\n safeTxHash: Hex,\n signature: Hex,\n): Promise<{ signer: Address; signature: Hex }> {\n assertSafeOwnerSignature(signature)\n const rs = sliceHex(signature, 0, 64)\n const v = hexToNumber(sliceHex(signature, 64, 65))\n const ethSign = v === 31 || v === 32\n const normalized = ethSign\n ? signature\n : concatHex([rs, numberToHex(v < 27 ? v + 27 : v, { size: 1 })])\n try {\n const signer = ethSign\n ? await recoverAddress({\n hash: hashMessage({ raw: safeTxHash }),\n signature: concatHex([rs, numberToHex(v - 4, { size: 1 })]),\n })\n : await recoverAddress({ hash: safeTxHash, signature: normalized })\n return { signer, signature: normalized }\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error)\n throw new SignedSafeTxError('INVALID_SIGNATURE', `signature recovery failed: ${reason}`)\n }\n}\n\n/**\n * Resolves an owner's signature over a plain call into an executable SafeTx,\n * given the Safe's on-chain `nonce`, `owners` and `threshold`. The signed nonce\n * is not part of the call, so it is searched from the on-chain nonce forward\n * (wallets may sign ahead of queued transactions).\n */\nexport async function resolveSignedSafeTx(params: {\n chainId: number\n safe: Address\n call: SafeCall\n signature: Hex\n state: { nonce: bigint; threshold: bigint; owners: readonly Address[] }\n nonceWindow?: number\n}): Promise<SignedSafeTx> {\n const safe = getAddress(params.safe)\n const nonceWindow = params.nonceWindow ?? 5\n const { nonce, threshold, owners } = params.state\n if (threshold !== 1n) {\n throw new SignedSafeTxError(\n 'THRESHOLD_NOT_MET',\n `Safe threshold is ${threshold}; a single owner signature cannot execute`,\n )\n }\n\n for (let offset = 0n; offset < BigInt(nonceWindow); offset++) {\n const tx = safeTxForCall(params.call, nonce + offset)\n const safeTxHash = hashSafeTx({ chainId: params.chainId, safe, tx })\n const { signer, signature } = await recoverSafeTxSigner(safeTxHash, params.signature)\n if (owners.some((owner) => isAddressEqual(owner, signer))) {\n return { safe, chainId: params.chainId, tx, safeTxHash, signer, signatures: signature }\n }\n }\n throw new SignedSafeTxError(\n 'SIGNATURE_MISMATCH',\n `signature does not recover to an owner of ${safe} for nonces ${nonce}..${nonce + BigInt(nonceWindow) - 1n}`,\n )\n}\n\n/** `execTransaction` arguments for a resolved signed SafeTx. */\nexport function execTransactionArgs(signed: SignedSafeTx) {\n const { tx } = signed\n return [\n tx.to,\n tx.value,\n tx.data,\n tx.operation,\n tx.safeTxGas,\n tx.baseGas,\n tx.gasPrice,\n tx.gasToken,\n tx.refundReceiver,\n signed.signatures,\n ] as const\n}\n"],"mappings":"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"}