permissionless 0.2.5 → 0.2.7

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.
Files changed (117) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/_cjs/accounts/biconomy/toBiconomySmartAccount.js +37 -13
  3. package/_cjs/accounts/biconomy/toBiconomySmartAccount.js.map +1 -1
  4. package/_cjs/accounts/kernel/toEcdsaKernelSmartAccount.js +2 -2
  5. package/_cjs/accounts/kernel/toEcdsaKernelSmartAccount.js.map +1 -1
  6. package/_cjs/accounts/kernel/utils/signMessage.js +1 -2
  7. package/_cjs/accounts/kernel/utils/signMessage.js.map +1 -1
  8. package/_cjs/accounts/kernel/utils/signTypedData.js +1 -2
  9. package/_cjs/accounts/kernel/utils/signTypedData.js.map +1 -1
  10. package/_cjs/accounts/light/toLightSmartAccount.js +1 -2
  11. package/_cjs/accounts/light/toLightSmartAccount.js.map +1 -1
  12. package/_cjs/accounts/safe/toSafeSmartAccount.js +1 -2
  13. package/_cjs/accounts/safe/toSafeSmartAccount.js.map +1 -1
  14. package/_cjs/accounts/simple/toSimpleSmartAccount.js +1 -2
  15. package/_cjs/accounts/simple/toSimpleSmartAccount.js.map +1 -1
  16. package/_cjs/accounts/trust/toTrustSmartAccount.js +2 -2
  17. package/_cjs/accounts/trust/toTrustSmartAccount.js.map +1 -1
  18. package/_cjs/actions/erc7579/accountId.js +1 -2
  19. package/_cjs/actions/erc7579/accountId.js.map +1 -1
  20. package/_cjs/actions/erc7579/installModule.js +1 -2
  21. package/_cjs/actions/erc7579/installModule.js.map +1 -1
  22. package/_cjs/actions/erc7579/installModules.js +1 -2
  23. package/_cjs/actions/erc7579/installModules.js.map +1 -1
  24. package/_cjs/actions/erc7579/isModuleInstalled.js +1 -2
  25. package/_cjs/actions/erc7579/isModuleInstalled.js.map +1 -1
  26. package/_cjs/actions/erc7579/supportsExecutionMode.js +2 -3
  27. package/_cjs/actions/erc7579/supportsExecutionMode.js.map +1 -1
  28. package/_cjs/actions/erc7579/supportsModule.js +2 -3
  29. package/_cjs/actions/erc7579/supportsModule.js.map +1 -1
  30. package/_cjs/actions/erc7579/uninstallModule.js +1 -2
  31. package/_cjs/actions/erc7579/uninstallModule.js.map +1 -1
  32. package/_cjs/actions/erc7579/uninstallModules.js +1 -2
  33. package/_cjs/actions/erc7579/uninstallModules.js.map +1 -1
  34. package/_cjs/actions/erc7579.js +2 -2
  35. package/_cjs/actions/erc7579.js.map +1 -1
  36. package/_cjs/actions/smartAccount/sendTransaction.js +1 -2
  37. package/_cjs/actions/smartAccount/sendTransaction.js.map +1 -1
  38. package/_cjs/actions/smartAccount/signMessage.js +1 -2
  39. package/_cjs/actions/smartAccount/signMessage.js.map +1 -1
  40. package/_cjs/actions/smartAccount/signTypedData.js +1 -2
  41. package/_cjs/actions/smartAccount/signTypedData.js.map +1 -1
  42. package/_cjs/actions/smartAccount/writeContract.js +1 -2
  43. package/_cjs/actions/smartAccount/writeContract.js.map +1 -1
  44. package/_cjs/clients/createSmartAccountClient.js +26 -10
  45. package/_cjs/clients/createSmartAccountClient.js.map +1 -1
  46. package/_cjs/clients/decorators/smartAccount.js +1 -2
  47. package/_cjs/clients/decorators/smartAccount.js.map +1 -1
  48. package/_cjs/clients/pimlico.js +1 -2
  49. package/_cjs/clients/pimlico.js.map +1 -1
  50. package/_cjs/experimental/pimlico/index.js +6 -0
  51. package/_cjs/experimental/pimlico/index.js.map +1 -0
  52. package/_cjs/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.js +126 -0
  53. package/_cjs/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.js.map +1 -0
  54. package/_cjs/utils/decodeNonce.js +1 -2
  55. package/_cjs/utils/decodeNonce.js.map +1 -1
  56. package/_cjs/utils/deepHexlify.js +2 -2
  57. package/_cjs/utils/deepHexlify.js.map +1 -1
  58. package/_cjs/utils/encode7579Calls.js +1 -2
  59. package/_cjs/utils/encode7579Calls.js.map +1 -1
  60. package/_cjs/utils/encodeInstallModule.js +1 -2
  61. package/_cjs/utils/encodeInstallModule.js.map +1 -1
  62. package/_cjs/utils/encodeNonce.js +1 -2
  63. package/_cjs/utils/encodeNonce.js.map +1 -1
  64. package/_cjs/utils/encodeUninstallModule.js +1 -2
  65. package/_cjs/utils/encodeUninstallModule.js.map +1 -1
  66. package/_cjs/utils/getAddressFromInitCodeOrPaymasterAndData.js +1 -2
  67. package/_cjs/utils/getAddressFromInitCodeOrPaymasterAndData.js.map +1 -1
  68. package/_cjs/utils/getPackedUserOperation.js +9 -9
  69. package/_cjs/utils/getPackedUserOperation.js.map +1 -1
  70. package/_cjs/utils/toOwner.js +1 -2
  71. package/_cjs/utils/toOwner.js.map +1 -1
  72. package/_esm/accounts/biconomy/toBiconomySmartAccount.js +39 -12
  73. package/_esm/accounts/biconomy/toBiconomySmartAccount.js.map +1 -1
  74. package/_esm/accounts/safe/toSafeSmartAccount.js.map +1 -1
  75. package/_esm/clients/createSmartAccountClient.js +26 -9
  76. package/_esm/clients/createSmartAccountClient.js.map +1 -1
  77. package/_esm/experimental/pimlico/index.js +3 -0
  78. package/_esm/experimental/pimlico/index.js.map +1 -0
  79. package/_esm/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.js +144 -0
  80. package/_esm/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.js.map +1 -0
  81. package/_types/accounts/biconomy/toBiconomySmartAccount.d.ts +2 -0
  82. package/_types/accounts/biconomy/toBiconomySmartAccount.d.ts.map +1 -1
  83. package/_types/accounts/kernel/utils/encodeCallData.d.ts.map +1 -1
  84. package/_types/accounts/kernel/utils/getNonceKey.d.ts.map +1 -1
  85. package/_types/accounts/kernel/utils/isKernelV2.d.ts.map +1 -1
  86. package/_types/accounts/safe/toSafeSmartAccount.d.ts +0 -1
  87. package/_types/accounts/safe/toSafeSmartAccount.d.ts.map +1 -1
  88. package/_types/actions/erc7579.d.ts +1 -249
  89. package/_types/actions/erc7579.d.ts.map +1 -1
  90. package/_types/actions/pimlico/getTokenQuotes.d.ts.map +1 -1
  91. package/_types/actions/pimlico/getUserOperationGasPrice.d.ts.map +1 -1
  92. package/_types/actions/pimlico/getUserOperationStatus.d.ts.map +1 -1
  93. package/_types/actions/pimlico/sendCompressedUserOperation.d.ts.map +1 -1
  94. package/_types/actions/pimlico/sponsorUserOperation.d.ts.map +1 -1
  95. package/_types/actions/pimlico/validateSponsorshipPolicies.d.ts.map +1 -1
  96. package/_types/actions/public/getAccountNonce.d.ts.map +1 -1
  97. package/_types/actions/public/getSenderAddress.d.ts.map +1 -1
  98. package/_types/clients/createSmartAccountClient.d.ts +4 -2
  99. package/_types/clients/createSmartAccountClient.d.ts.map +1 -1
  100. package/_types/clients/decorators/pimlico.d.ts.map +1 -1
  101. package/_types/clients/decorators/smartAccount.d.ts +16 -471
  102. package/_types/clients/decorators/smartAccount.d.ts.map +1 -1
  103. package/_types/experimental/pimlico/index.d.ts +3 -0
  104. package/_types/experimental/pimlico/index.d.ts.map +1 -0
  105. package/_types/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.d.ts +4 -0
  106. package/_types/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.d.ts.map +1 -0
  107. package/_types/utils/getPackedUserOperation.d.ts.map +1 -1
  108. package/_types/utils/getRequiredPrefund.d.ts.map +1 -1
  109. package/_types/utils/isSmartAccountDeployed.d.ts.map +1 -1
  110. package/accounts/biconomy/toBiconomySmartAccount.ts +85 -16
  111. package/accounts/safe/toSafeSmartAccount.ts +0 -1
  112. package/actions/smartAccount/sendTransaction.test.ts +129 -0
  113. package/clients/createSmartAccountClient.ts +53 -22
  114. package/experimental/pimlico/index.ts +2 -0
  115. package/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.test.ts +195 -0
  116. package/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.ts +270 -0
  117. package/package.json +6 -6
@@ -0,0 +1,270 @@
1
+ import {
2
+ type Address,
3
+ type Chain,
4
+ type Client,
5
+ type ContractFunctionParameters,
6
+ type Transport,
7
+ encodeFunctionData,
8
+ erc20Abi,
9
+ getAddress,
10
+ maxUint256
11
+ } from "viem"
12
+ import {
13
+ type BundlerClient,
14
+ type PrepareUserOperationParameters,
15
+ type PrepareUserOperationRequest,
16
+ type PrepareUserOperationReturnType,
17
+ type SmartAccount,
18
+ type UserOperation,
19
+ type UserOperationCall,
20
+ getPaymasterData as getPaymasterData_,
21
+ prepareUserOperation
22
+ } from "viem/account-abstraction"
23
+ import { getChainId as getChainId_ } from "viem/actions"
24
+ import { readContract } from "viem/actions"
25
+ import { getAction, parseAccount } from "viem/utils"
26
+ import { getTokenQuotes } from "../../../actions/pimlico"
27
+
28
+ export const prepareUserOperationForErc20Paymaster =
29
+ (pimlicoClient: Client) =>
30
+ async <
31
+ account extends SmartAccount | undefined,
32
+ const calls extends readonly unknown[],
33
+ const request extends PrepareUserOperationRequest<
34
+ account,
35
+ accountOverride,
36
+ calls
37
+ >,
38
+ accountOverride extends SmartAccount | undefined = undefined
39
+ >(
40
+ client: Client<Transport, Chain | undefined, account>,
41
+ parameters_: PrepareUserOperationParameters<
42
+ account,
43
+ accountOverride,
44
+ calls,
45
+ request
46
+ >
47
+ ): Promise<
48
+ PrepareUserOperationReturnType<account, accountOverride, calls, request>
49
+ > => {
50
+ const parameters = parameters_ as PrepareUserOperationParameters
51
+ const account_ = client.account
52
+
53
+ if (!account_) throw new Error("Account not found")
54
+ const account = parseAccount(account_)
55
+
56
+ const bundlerClient = client as unknown as BundlerClient
57
+
58
+ const paymasterContext = parameters.paymasterContext
59
+ ? parameters.paymasterContext
60
+ : bundlerClient?.paymasterContext
61
+
62
+ if (
63
+ typeof paymasterContext === "object" &&
64
+ paymasterContext !== null &&
65
+ "token" in paymasterContext &&
66
+ typeof paymasterContext.token === "string"
67
+ ) {
68
+ ////////////////////////////////////////////////////////////////////////////////
69
+ // Inject custom approval before calling prepareUserOperation
70
+ ////////////////////////////////////////////////////////////////////////////////
71
+
72
+ const token = getAddress(paymasterContext.token)
73
+
74
+ let chainId: number | undefined
75
+ async function getChainId(): Promise<number> {
76
+ if (chainId) return chainId
77
+ if (client.chain) return client.chain.id
78
+ const chainId_ = await getAction(
79
+ client,
80
+ getChainId_,
81
+ "getChainId"
82
+ )({})
83
+ chainId = chainId_
84
+ return chainId
85
+ }
86
+
87
+ const quotes = await getAction(
88
+ pimlicoClient,
89
+ getTokenQuotes,
90
+ "getTokenQuotes"
91
+ )({
92
+ tokens: [token],
93
+ chain:
94
+ pimlicoClient.chain ?? client.chain ?? account.client.chain,
95
+ entryPointAddress: account.entryPoint.address
96
+ })
97
+
98
+ const {
99
+ postOpGas,
100
+ exchangeRate,
101
+ paymaster: paymasterERC20Address
102
+ } = quotes[0]
103
+
104
+ const callsWithDummyApproval = [
105
+ {
106
+ abi: erc20Abi,
107
+ functionName: "approve",
108
+ args: [paymasterERC20Address, maxUint256], // dummy approval to ensure simulation passes
109
+ to: paymasterContext.token
110
+ },
111
+ ...(parameters.calls ? parameters.calls : [])
112
+ ]
113
+
114
+ if (parameters.callData) {
115
+ throw new Error(
116
+ "parameter callData is not supported with prepareUserOperationForErc20Paymaster"
117
+ )
118
+ }
119
+
120
+ ////////////////////////////////////////////////////////////////////////////////
121
+ // Call prepareUserOperation
122
+ ////////////////////////////////////////////////////////////////////////////////
123
+
124
+ const userOperation = await getAction(
125
+ client,
126
+ prepareUserOperation,
127
+ "prepareUserOperation"
128
+ )({
129
+ ...parameters,
130
+ calls: callsWithDummyApproval
131
+ } as unknown as PrepareUserOperationParameters)
132
+
133
+ ////////////////////////////////////////////////////////////////////////////////
134
+ // Call pimlico_getTokenQuotes and calculate the approval amount needed for op
135
+ ////////////////////////////////////////////////////////////////////////////////
136
+
137
+ const maxFeePerGas = userOperation.maxFeePerGas
138
+
139
+ const userOperationMaxGas =
140
+ userOperation.preVerificationGas +
141
+ userOperation.callGasLimit +
142
+ userOperation.verificationGasLimit +
143
+ (userOperation.paymasterPostOpGasLimit || 0n) +
144
+ (userOperation.paymasterVerificationGasLimit || 0n)
145
+
146
+ const userOperationMaxCost = userOperationMaxGas * maxFeePerGas
147
+
148
+ // using formula here https://github.com/pimlicolabs/singleton-paymaster/blob/main/src/base/BaseSingletonPaymaster.sol#L334-L341
149
+ const maxCostInToken =
150
+ ((userOperationMaxCost + postOpGas * maxFeePerGas) *
151
+ exchangeRate) /
152
+ BigInt(1e18)
153
+
154
+ ////////////////////////////////////////////////////////////////////////////////
155
+ // Check if we need to approve the token
156
+ // If the user has existing approval that is sufficient, skip approval injection
157
+ ////////////////////////////////////////////////////////////////////////////////
158
+
159
+ const publicClient = account.client
160
+
161
+ const allowance = await getAction(
162
+ publicClient,
163
+ readContract,
164
+ "readContract"
165
+ )({
166
+ abi: erc20Abi,
167
+ functionName: "allowance",
168
+ args: [account.address, paymasterERC20Address],
169
+ address: token
170
+ })
171
+
172
+ const hasSufficientApproval = allowance >= maxCostInToken
173
+
174
+ const finalCalls = hasSufficientApproval
175
+ ? parameters.calls
176
+ : [
177
+ {
178
+ abi: erc20Abi,
179
+ functionName: "approve",
180
+ args: [paymasterERC20Address, maxCostInToken],
181
+ to: paymasterContext.token
182
+ },
183
+ ...parameters.calls
184
+ ]
185
+
186
+ userOperation.callData = await account.encodeCalls(
187
+ finalCalls.map((call_) => {
188
+ const call = call_ as
189
+ | UserOperationCall
190
+ | (ContractFunctionParameters & {
191
+ to: Address
192
+ value: bigint
193
+ })
194
+ if ("abi" in call)
195
+ return {
196
+ data: encodeFunctionData(call),
197
+ to: call.to,
198
+ value: call.value
199
+ } as UserOperationCall
200
+ return call as UserOperationCall
201
+ })
202
+ )
203
+ parameters.calls = finalCalls
204
+
205
+ ////////////////////////////////////////////////////////////////////////////////
206
+ // Declare Paymaster properties. (taken from viem)
207
+ ////////////////////////////////////////////////////////////////////////////////
208
+
209
+ const paymaster = parameters.paymaster ?? bundlerClient?.paymaster
210
+ const { getPaymasterData } = (() => {
211
+ // If `paymaster: true`, we will assume the Bundler Client supports Paymaster Actions.
212
+ if (paymaster === true)
213
+ return {
214
+ getPaymasterData: (parameters: any) =>
215
+ getAction(
216
+ bundlerClient,
217
+ getPaymasterData_,
218
+ "getPaymasterData"
219
+ )(parameters)
220
+ }
221
+
222
+ // If Actions are passed to `paymaster` (via Paymaster Client or directly), we will use them.
223
+ if (
224
+ typeof paymaster === "object" &&
225
+ paymaster.getPaymasterData
226
+ ) {
227
+ const { getPaymasterData } = paymaster
228
+ return {
229
+ getPaymasterData
230
+ }
231
+ }
232
+
233
+ throw new Error(
234
+ "Expected paymaster: cannot sponsor ERC-20 without paymaster"
235
+ )
236
+ })()
237
+
238
+ ////////////////////////////////////////////////////////////////////////////////
239
+ // Re-calculate Paymaster data fields.
240
+ ////////////////////////////////////////////////////////////////////////////////
241
+
242
+ const paymasterData = await getPaymasterData({
243
+ chainId: await getChainId(),
244
+ entryPointAddress: account.entryPoint.address,
245
+ context: paymasterContext,
246
+ ...(userOperation as UserOperation)
247
+ })
248
+
249
+ return {
250
+ ...userOperation,
251
+ ...paymasterData
252
+ } as unknown as PrepareUserOperationReturnType<
253
+ account,
254
+ accountOverride,
255
+ calls,
256
+ request
257
+ >
258
+ }
259
+
260
+ return (await getAction(
261
+ client,
262
+ prepareUserOperation,
263
+ "prepareUserOperation"
264
+ )(parameters)) as unknown as PrepareUserOperationReturnType<
265
+ account,
266
+ accountOverride,
267
+ calls,
268
+ request
269
+ >
270
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "permissionless",
3
- "version": "0.2.5",
3
+ "version": "0.2.7",
4
4
  "author": "Pimlico",
5
5
  "homepage": "https://docs.pimlico.io/permissionless",
6
6
  "repository": "github:pimlicolabs/permissionless.js",
@@ -70,13 +70,13 @@
70
70
  "import": "./_esm/errors/index.js",
71
71
  "default": "./_cjs/errors/index.js"
72
72
  },
73
- "./experimental": {
74
- "types": "./_types/experimental/index.d.ts",
75
- "import": "./_esm/experimental/index.js",
76
- "default": "./_cjs/experimental/index.js"
73
+ "./experimental/pimlico": {
74
+ "types": "./_types/experimental/pimlico/index.d.ts",
75
+ "import": "./_esm/experimental/pimlico/index.js",
76
+ "default": "./_cjs/experimental/pimlico/index.js"
77
77
  }
78
78
  },
79
79
  "peerDependencies": {
80
- "viem": "^2.20.0"
80
+ "viem": "^2.21.2"
81
81
  }
82
82
  }