abstractionkit 0.3.1 → 0.3.3

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/CHANGELOG.md CHANGED
@@ -1,5 +1,135 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.3
4
+
5
+ ### New Features
6
+
7
+ - **`TokenQuote` type** exported from the package root: `{ token: string; exchangeRate: bigint; tokenCost: bigint }`. Surfaces the exchange rate and maximum token cost the paymaster applied when paying gas with an ERC-20 token, so consumers can display the cost to users or log/meter it without a second RPC round-trip.
8
+ - **`CandidePaymaster.createTokenPaymasterUserOperation` and `Erc7677Paymaster.createPaymasterUserOperation` now return `tokenQuote`** alongside the UserOperation. Populated on the token-payment flow; absent on sponsored flows and on Candide's `signingPhase: "finalize"` path (no gas estimation → no cost computation).
9
+ - **`skipGasEstimation` flag on `createUserOperation` overrides** for `SafeAccount`, `Calibur7702Account`, and `Simple7702Account`. When set, the UserOperation is returned with a dummy signature and zero (or override-provided) gas limits, skipping the bundler's `eth_estimateUserOperationGas` roundtrip. Useful when gas estimation is run separately, for example by a paymaster sponsorship call that returns its own gas limits.
10
+ - **`SponsorInfo` type** exported from the package root. Represents the raw `{ name, icon? }` shape returned by paymasters per ERC-7677; `CandidePaymaster` normalizes it into the public `SponsorMetadata` shape.
11
+
12
+ ### Breaking Changes
13
+
14
+ - **Three paymaster methods changed return shape** from a raw UserOperation / tuple to a named-field object. All now return `{ userOperation, tokenQuote? | sponsorMetadata? }`:
15
+ - `CandidePaymaster.createTokenPaymasterUserOperation` — returns `{ userOperation, tokenQuote? }` (was `SameUserOp<T>`).
16
+ - `CandidePaymaster.createSponsorPaymasterUserOperation` — returns `{ userOperation, sponsorMetadata? }` (was `[SameUserOp<T>, SponsorMetadata | undefined]`).
17
+ - `Erc7677Paymaster.createPaymasterUserOperation` — returns `{ userOperation, tokenQuote? }` (was `SameUserOp<T>`).
18
+
19
+ Migration:
20
+ ```ts
21
+ // Before
22
+ const [sponsoredOp, sponsorMetadata] = await paymaster.createSponsorPaymasterUserOperation(...);
23
+ const tokenOp = await paymaster.createTokenPaymasterUserOperation(...);
24
+ const userOp = await erc7677.createPaymasterUserOperation(...);
25
+
26
+ // After
27
+ const { userOperation: sponsoredOp, sponsorMetadata } = await paymaster.createSponsorPaymasterUserOperation(...);
28
+ const { userOperation: tokenOp, tokenQuote } = await paymaster.createTokenPaymasterUserOperation(...);
29
+ const { userOperation, tokenQuote } = await erc7677.createPaymasterUserOperation(...);
30
+ ```
31
+ - **`CandidePaymasterContext` moved back to a dedicated parameter** on `CandidePaymaster.createSponsorPaymasterUserOperation` and `createTokenPaymasterUserOperation`. The `context` field was removed from `GasPaymasterUserOperationOverrides`, and `context` is now the second-to-last argument (optional) on both methods, with `overrides` as the last argument. Migration:
32
+ ```ts
33
+ // Before (0.3.2): context nested inside overrides
34
+ await paymaster.createSponsorPaymasterUserOperation(
35
+ smartAccount, userOp, bundlerRpc, sponsorshipPolicyId,
36
+ { context: { signingPhase: "commit" }, maxFeePerGasMultiplier: 110n },
37
+ );
38
+ await paymaster.createTokenPaymasterUserOperation(
39
+ smartAccount, userOp, tokenAddress, bundlerRpc,
40
+ { context: { signingPhase: "commit" }, maxFeePerGasMultiplier: 110n },
41
+ );
42
+
43
+ // After (0.3.3): context is a dedicated argument
44
+ await paymaster.createSponsorPaymasterUserOperation(
45
+ smartAccount, userOp, bundlerRpc, sponsorshipPolicyId,
46
+ { signingPhase: "commit" },
47
+ { maxFeePerGasMultiplier: 110n },
48
+ );
49
+ // For createTokenPaymasterUserOperation, `context` is optional: the method
50
+ // always derives `context.token` from the `tokenAddress` argument, so pass
51
+ // `undefined` unless you need other context fields (e.g. `signingPhase`).
52
+ await paymaster.createTokenPaymasterUserOperation(
53
+ smartAccount, userOp, tokenAddress, bundlerRpc,
54
+ undefined,
55
+ { maxFeePerGasMultiplier: 110n },
56
+ );
57
+ ```
58
+
59
+ ### Bug Fixes
60
+
61
+ - **`CandidePaymaster` now parses sponsor info per ERC-7677.** Paymasters return sponsor info under `sponsor: { name, icon? }` (singular `icon`); the previous code read a non-standard `sponsorMetadata` key and therefore always returned `undefined`. The raw response is now normalized into the public `SponsorMetadata` shape (`{ name, description, url, icons[] }`).
62
+
63
+ ## 0.3.2
64
+
65
+ ### New Features
66
+
67
+ - **`signUserOperationWithSigner(s)` + `ExternalSigner` (capability-oriented signing API)**: new async method on every account class for integrating viem, ethers Signers, hardware wallets, HSMs, MPC, WebAuthn, or Uint8Array-only signers without passing raw private keys. Each account declares its accepted schemes via a static `ACCEPTED_SIGNING_SCHEMES: ReadonlyArray<"hash" | "typedData">`, and incompatible signers fail offline with an actionable error. The method naming mirrors the parameter arity:
68
+ - Safe accounts (multi-signer): `signUserOperationWithSigners(op, signers[], chainId)` — plural.
69
+ - Simple7702 / Calibur (single signer): `signUserOperationWithSigner(op, signer, chainId)` — singular.
70
+
71
+ Call-site is one line:
72
+ ```ts
73
+ import { fromViem } from "abstractionkit"
74
+ userOp.signature = await safe.signUserOperationWithSigners(
75
+ userOp, [fromViem(account)], chainId,
76
+ )
77
+ ```
78
+
79
+ - **`ExternalSigner` interface**: `{ address, signHash?, signTypedData? }` discriminated union that enforces at least one of the two methods at compile time. Accepts any signer that matches the shape (viem local account, viem WalletClient, ethers Wallet, hardware wallet, MPC, WebAuthn, Uint8Array-held keys). The library has zero runtime dependency on viem or ethers for this surface.
80
+ - **`fromPrivateKey(pk)` / `fromViem(account)` / `fromEthersWallet(wallet)` / `fromViemWalletClient(client)` adapters**: one-line factories returning an `ExternalSigner`. Structural types only. `fromViem` / `fromViemWalletClient` require viem ≥ 2.0; `fromEthersWallet` requires ethers ≥ 6.0.
81
+ - **`SignHashFn` / `SignTypedDataFn` / `TypedData` / `SigningScheme` / `SignContext` / `MultiOpSignContext` types** exported from the package root for implementers of custom signers.
82
+ - **`SignContext` forwarded to signers, narrowly typed per signing path**: signers receive a context as the second arg of `signHash` / `signTypedData` so custom validator implementations can inspect the userOp. `Signer<C>` is generic over context (default `C = SignContext` for single-op `{userOperation, chainId, entryPoint}`; opt into `ExternalSigner<MultiOpSignContext>` for `signUserOperationsWithSigners`'s `{userOperations[], entryPoint}`). Built-in adapters return `Signer<unknown>` and work everywhere. See `src/signer/types.ts`.
83
+ - **`SafeMultiChainSigAccountV1.signUserOperationsWithSigners`**: new async multi-op variant that signs a Merkle-rooted bundle of UserOperations with a single signature across chains, using `ExternalSigner[]`.
84
+
85
+ ### Breaking Changes
86
+
87
+ > **Note on versioning.** The callback-API removal below is a breaking change for callers of `signUserOperationWithSigner`'s prior callback shape on `Calibur7702Account`. Calibur is not yet in use in any production environment; we're communicating directly with the developers currently building against it to coordinate the migration.
88
+
89
+ - **`SafeAccount.baseSignSingleUserOperation` is now `protected static`.** Previously `public static`, which leaked an internal helper into the package surface. All callers should use the version-specific subclass methods that wrap it (`SafeAccountV0_2_0#signUserOperation`, `SafeAccountV0_3_0#signUserOperation`, etc.) — they auto-inject the correct entrypoint and 4337 module addresses. Migration:
90
+ ```ts
91
+ // Before:
92
+ const sig = SafeAccount.baseSignSingleUserOperation(
93
+ op, [pk], chainId,
94
+ SafeAccountV0_3_0.DEFAULT_ENTRYPOINT_ADDRESS,
95
+ SafeAccountV0_3_0.DEFAULT_SAFE_4337_MODULE_ADDRESS,
96
+ );
97
+ // After:
98
+ const sig = safeV3.signUserOperation(op, [pk], chainId);
99
+ ```
100
+ `baseSignUserOperationWithSigners` (introduced earlier in this Unreleased window) is also `protected static` for the same reason; no migration needed since it was never on a released `latest` tag.
101
+ - **`ViemLocalAccountLike` / `ViemWalletClientLike` / `EthersWalletLike` are no longer exported.** They're internal structural shapes the adapters match against; pass concrete viem / ethers instances directly to `fromViem` / `fromViemWalletClient` / `fromEthersWallet`. If you need to type a wrapper, use `Parameters<typeof fromViem>[0]` (etc.).
102
+ - **Callback signing API removed.** `signUserOperationWithSigner(op, callback, chainId)` as introduced in the original signer PR is gone, along with the `SignerFunction`, `AddressedSignerFunction`, `SignerInput`, `SignerResult`, and `SignerTypedData` types. The callback method name is now reused for the new capability-oriented API on single-signer accounts (Simple7702, Calibur) with a different parameter shape. Migration:
103
+ ```ts
104
+ // Before:
105
+ const signer = async ({ userOpHash }) => ({
106
+ signature: wallet.signingKey.sign(userOpHash).serialized,
107
+ });
108
+ userOp.signature = await account.signUserOperationWithSigner(userOp, signer, chainId);
109
+
110
+ // After — Simple7702 / Calibur (single signer):
111
+ import { fromEthersWallet } from "abstractionkit";
112
+ userOp.signature = await account.signUserOperationWithSigner(
113
+ userOp, fromEthersWallet(wallet), chainId,
114
+ );
115
+
116
+ // After — Safe accounts (multi-signer, plural method name):
117
+ userOp.signature = await safe.signUserOperationWithSigners(
118
+ userOp, [fromEthersWallet(wallet)], chainId,
119
+ );
120
+ ```
121
+
122
+ ### Migration: Signing with a raw private key
123
+
124
+ The existing sync `signUserOperation(op, pk[] | pk, chainId): string` method on every account **is untouched**. If your code passes a hex private-key string directly, no change needed. The new `signUserOperationWithSigner(s)` methods are Signers-only — they do NOT accept bare pk strings. To sign with a pk string via the new API, wrap explicitly:
125
+
126
+ ```ts
127
+ import { fromPrivateKey } from "abstractionkit";
128
+ userOp.signature = await safe.signUserOperationWithSigners(
129
+ userOp, [fromPrivateKey(pk)], chainId,
130
+ );
131
+ ```
132
+
3
133
  ## 0.3.1
4
134
 
5
135
  ### New Features
package/README.md CHANGED
@@ -38,10 +38,10 @@ npm install abstractionkit
38
38
 
39
39
  ### Upgrading to v0.3.0
40
40
 
41
- v0.3.0 is a major release. Two API changes are likely to break existing paymaster code:
41
+ v0.3.0 is a major release. The following API changes are likely to break existing paymaster code:
42
42
 
43
- - `CandidePaymaster.createSponsorPaymasterUserOperation(...)` now takes `smartAccount` as the **first** argument: `(smartAccount, userOp, bundlerRpc, sponsorshipPolicyId?, overrides?)`.
44
- - `CandidePaymasterContext` is no longer a separate argument. Pass it via `overrides.context` on `GasPaymasterUserOperationOverrides`.
43
+ - `CandidePaymaster.createSponsorPaymasterUserOperation(...)` now takes `smartAccount` as the **first** argument: `(smartAccount, userOp, bundlerRpc, sponsorshipPolicyId?, context?, overrides?)`.
44
+ - `CandidePaymaster.createTokenPaymasterUserOperation(...)` adds a dedicated `context?` argument before `overrides?`: `(smartAccount, userOp, tokenAddress, bundlerRpc, context?, overrides?)`. Callers that previously passed `overrides` positionally at argument 5 must insert `undefined` (or an explicit context) so `overrides` shifts to argument 6.
45
45
 
46
46
  See [CHANGELOG.md](./CHANGELOG.md) for the full list of new features, renames, type export changes, and fixes.
47
47
 
@@ -143,12 +143,13 @@ const userOp = await smartAccount.createUserOperation(
143
143
 
144
144
  // Sponsor it. Sets paymaster fields and re-estimates gas.
145
145
  // Note: as of v0.3.0, smartAccount is the first argument.
146
- const [sponsoredOp] = await paymaster.createSponsorPaymasterUserOperation(
146
+ const { userOperation: sponsoredOp, sponsorMetadata } = await paymaster.createSponsorPaymasterUserOperation(
147
147
  smartAccount,
148
148
  userOp,
149
149
  bundlerRpc,
150
150
  sponsorshipPolicyId,
151
- // overrides (optional, includes context for parallel signing)
151
+ // context (optional e.g. { signingPhase: "commit" } for EP v0.9 parallel signing)
152
+ // overrides (optional — gas limits and multipliers)
152
153
  );
153
154
 
154
155
  // Sign and send as usual
@@ -173,12 +174,14 @@ const userOp = await smartAccount.createUserOperation(
173
174
  // Automatically prepends token approval + sets paymaster fields.
174
175
  // For tokens like USDT that require resetting allowance to 0 first, pass
175
176
  // { resetApproval: true } in the overrides.
176
- const tokenOp = await paymaster.createTokenPaymasterUserOperation(
177
+ // `tokenQuote` carries the exchange rate and max token cost used for the approval.
178
+ const { userOperation: tokenOp, tokenQuote } = await paymaster.createTokenPaymasterUserOperation(
177
179
  smartAccount,
178
180
  userOp,
179
181
  gasTokenAddress,
180
182
  bundlerRpc,
181
- // overrides (optional)
183
+ // context (optional)
184
+ // overrides (optional — gas limits, multipliers, resetApproval)
182
185
  );
183
186
 
184
187
  tokenOp.signature = smartAccount.signUserOperation(tokenOp, [ownerPrivateKey], chainId);
@@ -187,20 +190,20 @@ const response = await smartAccount.sendUserOperation(tokenOp, bundlerRpc);
187
190
 
188
191
  ### Pass paymaster context (sponsorship policy, parallel signing)
189
192
 
190
- As of v0.3.0, `CandidePaymasterContext` is passed via the `overrides.context` field on `GasPaymasterUserOperationOverrides`. Previously it was a separate top level argument.
193
+ `CandidePaymasterContext` is passed as its own argument, separate from gas overrides.
191
194
 
192
195
  ```typescript
193
- const [sponsoredOp] = await paymaster.createSponsorPaymasterUserOperation(
196
+ const { userOperation: sponsoredOp } = await paymaster.createSponsorPaymasterUserOperation(
194
197
  smartAccount,
195
198
  userOp,
196
199
  bundlerRpc,
197
200
  sponsorshipPolicyId,
198
201
  {
199
- context: {
200
- // For EntryPoint v0.9 parallel signing flows:
201
- // signingPhase: "commit" | "finalize",
202
- },
203
- // gas overrides also live here:
202
+ // For EntryPoint v0.9 parallel signing flows:
203
+ // signingPhase: "commit" | "finalize",
204
+ },
205
+ {
206
+ // gas overrides:
204
207
  callGasLimitPercentageMultiplier: 110,
205
208
  },
206
209
  );