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
@@ -15,6 +15,10 @@ import {
15
15
  type LocalAccount,
16
16
  encodeAbiParameters,
17
17
  encodeFunctionData,
18
+ encodePacked,
19
+ getContractAddress,
20
+ hexToBigInt,
21
+ keccak256,
18
22
  parseAbiParameters
19
23
  } from "viem"
20
24
  import {
@@ -27,10 +31,12 @@ import {
27
31
  } from "viem/account-abstraction"
28
32
  import { signMessage } from "viem/actions"
29
33
  import { getAccountNonce } from "../../actions/public/getAccountNonce"
30
- import { getSenderAddress } from "../../actions/public/getSenderAddress"
31
34
  import { toOwner } from "../../utils/toOwner"
32
35
  import { BiconomyAbi, FactoryAbi } from "./abi/BiconomySmartAccountAbi"
33
36
 
37
+ const BICONOMY_PROXY_CREATION_CODE =
38
+ "0x6080346100aa57601f61012038819003918201601f19168301916001600160401b038311848410176100af578084926020946040528339810103126100aa57516001600160a01b0381168082036100aa5715610065573055604051605a90816100c68239f35b60405162461bcd60e51b815260206004820152601e60248201527f496e76616c696420696d706c656d656e746174696f6e206164647265737300006044820152606490fd5b600080fd5b634e487b7160e01b600052604160045260246000fdfe608060405230546000808092368280378136915af43d82803e156020573d90f35b3d90fdfea2646970667358221220a03b18dce0be0b4c9afe58a9eb85c35205e2cf087da098bbf1d23945bf89496064736f6c63430008110033"
39
+
34
40
  /**
35
41
  * The account creation ABI for Biconomy Smart Account (from the biconomy SmartAccountFactory)
36
42
  */
@@ -41,10 +47,15 @@ import { BiconomyAbi, FactoryAbi } from "./abi/BiconomySmartAccountAbi"
41
47
  const BICONOMY_ADDRESSES: {
42
48
  ECDSA_OWNERSHIP_REGISTRY_MODULE: Address
43
49
  FACTORY_ADDRESS: Address
50
+ ACCOUNT_V2_0_LOGIC: Address
51
+ DEFAULT_FALLBACK_HANDLER_ADDRESS: Address
44
52
  } = {
45
53
  ECDSA_OWNERSHIP_REGISTRY_MODULE:
46
54
  "0x0000001c5b32F37F5beA87BDD5374eB2aC54eA8e",
47
- FACTORY_ADDRESS: "0x000000a56Aaca3e9a4C479ea6b6CD0DbcB6634F5"
55
+ FACTORY_ADDRESS: "0x000000a56Aaca3e9a4C479ea6b6CD0DbcB6634F5",
56
+ ACCOUNT_V2_0_LOGIC: "0x0000002512019Dafb59528B82CB92D3c5D2423aC",
57
+ DEFAULT_FALLBACK_HANDLER_ADDRESS:
58
+ "0x0bBa6d96BD616BedC6BFaa341742FD43c60b83C1"
48
59
  }
49
60
 
50
61
  /**
@@ -98,6 +109,8 @@ export type ToBiconomySmartAccountParameters = Prettify<{
98
109
  index?: bigint
99
110
  factoryAddress?: Address
100
111
  ecdsaModuleAddress?: Address
112
+ accountLogicAddress?: Address
113
+ fallbackHandlerAddress?: Address
101
114
  }>
102
115
 
103
116
  export type BiconomySmartAccountImplementation = Assign<
@@ -109,6 +122,59 @@ export type ToBiconomySmartAccountReturnType = Prettify<
109
122
  SmartAccount<BiconomySmartAccountImplementation>
110
123
  >
111
124
 
125
+ const getAccountAddress = async ({
126
+ factoryAddress,
127
+ accountLogicAddress,
128
+ fallbackHandlerAddress,
129
+ ecdsaModuleAddress,
130
+ owner,
131
+ index = BigInt(0)
132
+ }: {
133
+ factoryAddress: Address
134
+ accountLogicAddress: Address
135
+ fallbackHandlerAddress: Address
136
+ ecdsaModuleAddress: Address
137
+ owner: Address
138
+ index?: bigint
139
+ }): Promise<Address> => {
140
+ // Build the module setup data
141
+ const ecdsaOwnershipInitData = encodeFunctionData({
142
+ abi: BiconomyAbi,
143
+ functionName: "initForSmartAccount",
144
+ args: [owner]
145
+ })
146
+
147
+ // Build account init code
148
+ const initialisationData = encodeFunctionData({
149
+ abi: BiconomyAbi,
150
+ functionName: "init",
151
+ args: [
152
+ fallbackHandlerAddress,
153
+ ecdsaModuleAddress,
154
+ ecdsaOwnershipInitData
155
+ ]
156
+ })
157
+
158
+ const deploymentCode = encodePacked(
159
+ ["bytes", "uint256"],
160
+ [BICONOMY_PROXY_CREATION_CODE, hexToBigInt(accountLogicAddress)]
161
+ )
162
+
163
+ const salt = keccak256(
164
+ encodePacked(
165
+ ["bytes32", "uint256"],
166
+ [keccak256(encodePacked(["bytes"], [initialisationData])), index]
167
+ )
168
+ )
169
+
170
+ return getContractAddress({
171
+ from: factoryAddress,
172
+ salt,
173
+ bytecode: deploymentCode,
174
+ opcode: "CREATE2"
175
+ })
176
+ }
177
+
112
178
  /**
113
179
  * Build a Biconomy modular smart account from a private key, that use the ECDSA signer behind the scene
114
180
  * @param client
@@ -122,7 +188,16 @@ export type ToBiconomySmartAccountReturnType = Prettify<
122
188
  export async function toBiconomySmartAccount(
123
189
  parameters: ToBiconomySmartAccountParameters
124
190
  ): Promise<ToBiconomySmartAccountReturnType> {
125
- const { owners, client, index = 0n, address } = parameters
191
+ const {
192
+ owners,
193
+ client,
194
+ index = 0n,
195
+ address,
196
+ accountLogicAddress = BICONOMY_ADDRESSES.ACCOUNT_V2_0_LOGIC,
197
+ fallbackHandlerAddress = BICONOMY_ADDRESSES.DEFAULT_FALLBACK_HANDLER_ADDRESS,
198
+ ecdsaModuleAddress = BICONOMY_ADDRESSES.ECDSA_OWNERSHIP_REGISTRY_MODULE,
199
+ factoryAddress = BICONOMY_ADDRESSES.FACTORY_ADDRESS
200
+ } = parameters
126
201
 
127
202
  const localOwner = await toOwner({ owner: owners[0] })
128
203
 
@@ -132,15 +207,8 @@ export async function toBiconomySmartAccount(
132
207
  version: parameters.entryPoint?.version ?? "0.6"
133
208
  }
134
209
 
135
- const factoryAddress =
136
- parameters.factoryAddress ?? BICONOMY_ADDRESSES.FACTORY_ADDRESS
137
-
138
210
  let accountAddress: Address | undefined = address
139
211
 
140
- const ecdsaModuleAddress =
141
- parameters.ecdsaModuleAddress ??
142
- BICONOMY_ADDRESSES.ECDSA_OWNERSHIP_REGISTRY_MODULE
143
-
144
212
  const getFactoryArgs = async () => {
145
213
  return {
146
214
  factory: factoryAddress,
@@ -159,13 +227,14 @@ export async function toBiconomySmartAccount(
159
227
  async getAddress() {
160
228
  if (accountAddress) return accountAddress
161
229
 
162
- const { factory, factoryData } = await getFactoryArgs()
163
-
164
230
  // Get the sender address based on the init code
165
- accountAddress = await getSenderAddress(client, {
166
- factory,
167
- factoryData,
168
- entryPointAddress: entryPoint.address
231
+ accountAddress = await getAccountAddress({
232
+ owner: localOwner.address,
233
+ ecdsaModuleAddress,
234
+ factoryAddress,
235
+ accountLogicAddress,
236
+ fallbackHandlerAddress,
237
+ index
169
238
  })
170
239
 
171
240
  return accountAddress
@@ -951,7 +951,6 @@ export type ToSafeSmartAccountParameters<
951
951
  version: entryPointVersion
952
952
  }
953
953
  safe4337ModuleAddress?: Address
954
- erc7569LaunchpadAddress?: Address
955
954
  erc7579LaunchpadAddress?: TErc7579
956
955
  safeProxyFactoryAddress?: Address
957
956
  safeSingletonAddress?: Address
@@ -74,6 +74,8 @@ describe.each(getCoreSmartAccounts())(
74
74
  entryPoint: {
75
75
  version: "0.7"
76
76
  },
77
+ privateKey:
78
+ "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", // anvil private key
77
79
  ...rpc
78
80
  })
79
81
 
@@ -114,5 +116,132 @@ describe.each(getCoreSmartAccounts())(
114
116
  expect(receipt2.status).toBe("success")
115
117
  }
116
118
  )
119
+
120
+ testWithRpc.skipIf(!supportsEntryPointV06)(
121
+ "sendTransaction_v06 post deployment",
122
+ async ({ rpc }) => {
123
+ const { anvilRpc } = rpc
124
+
125
+ await (async () => {
126
+ const smartClient = await getSmartAccountClient({
127
+ entryPoint: {
128
+ version: "0.6"
129
+ },
130
+ privateKey:
131
+ "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", // anvil private key
132
+ ...rpc
133
+ })
134
+
135
+ const transactionHash = await sendTransaction(smartClient, {
136
+ to: zeroAddress,
137
+ data: "0x",
138
+ value: 0n
139
+ })
140
+
141
+ expect(transactionHash).toBeTruthy()
142
+
143
+ const publicClient = getPublicClient(anvilRpc)
144
+
145
+ const receipt = await publicClient.getTransactionReceipt({
146
+ hash: transactionHash
147
+ })
148
+
149
+ expect(receipt).toBeTruthy()
150
+ expect(receipt.transactionHash).toBe(transactionHash)
151
+ expect(receipt.status).toBe("success")
152
+ })()
153
+
154
+ const smartClient = await getSmartAccountClient({
155
+ entryPoint: {
156
+ version: "0.6"
157
+ },
158
+ privateKey:
159
+ "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", // anvil private key
160
+ ...rpc
161
+ })
162
+
163
+ const publicClient = getPublicClient(anvilRpc)
164
+
165
+ // -- second transaction after deployment
166
+ const transactionHash2 = await sendTransaction(smartClient, {
167
+ to: zeroAddress,
168
+ data: "0x",
169
+ value: 0n
170
+ })
171
+
172
+ expect(transactionHash2).toBeTruthy()
173
+
174
+ const receipt2 = await publicClient.getTransactionReceipt({
175
+ hash: transactionHash2
176
+ })
177
+
178
+ expect(receipt2).toBeTruthy()
179
+ expect(receipt2.transactionHash).toBe(transactionHash2)
180
+ expect(receipt2.status).toBe("success")
181
+ }
182
+ )
183
+
184
+ testWithRpc.skipIf(!supportsEntryPointV07)(
185
+ "sendTransaction_v07 post deployment",
186
+ async ({ rpc }) => {
187
+ const { anvilRpc } = rpc
188
+
189
+ await (async () => {
190
+ const smartClient = await getSmartAccountClient({
191
+ entryPoint: {
192
+ version: "0.7"
193
+ },
194
+ ...rpc
195
+ })
196
+
197
+ const transactionHash = await sendTransaction(smartClient, {
198
+ to: zeroAddress,
199
+ data: "0x",
200
+ value: 0n
201
+ })
202
+
203
+ expect(transactionHash).toBeTruthy()
204
+
205
+ const publicClient = getPublicClient(anvilRpc)
206
+
207
+ const receipt = await publicClient.getTransactionReceipt({
208
+ hash: transactionHash
209
+ })
210
+
211
+ expect(receipt).toBeTruthy()
212
+ expect(receipt.transactionHash).toBe(transactionHash)
213
+ expect(receipt.status).toBe("success")
214
+ })()
215
+
216
+ const smartClient = await getSmartAccountClient({
217
+ entryPoint: {
218
+ version: "0.7"
219
+ },
220
+ privateKey:
221
+ "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", // anvil private key
222
+ ...rpc
223
+ })
224
+
225
+ const publicClient = getPublicClient(anvilRpc)
226
+
227
+ const transactionHash2 = await sendTransaction(smartClient, {
228
+ to: zeroAddress,
229
+ data: "0x",
230
+ value: 0n
231
+ })
232
+
233
+ // -- second transaction after deployment
234
+
235
+ expect(transactionHash2).toBeTruthy()
236
+
237
+ const receipt2 = await publicClient.getTransactionReceipt({
238
+ hash: transactionHash2
239
+ })
240
+
241
+ expect(receipt2).toBeTruthy()
242
+ expect(receipt2.transactionHash).toBe(transactionHash2)
243
+ expect(receipt2.status).toBe("success")
244
+ }
245
+ )
117
246
  }
118
247
  )
@@ -1,20 +1,23 @@
1
- import type {
2
- BundlerRpcSchema,
3
- Chain,
4
- Client,
5
- ClientConfig,
6
- EstimateFeesPerGasReturnType,
7
- Prettify,
8
- RpcSchema,
9
- Transport
1
+ import {
2
+ type BundlerRpcSchema,
3
+ type Chain,
4
+ type Client,
5
+ type ClientConfig,
6
+ type EstimateFeesPerGasReturnType,
7
+ type Prettify,
8
+ type RpcSchema,
9
+ type Transport,
10
+ createClient
10
11
  } from "viem"
11
12
  import {
12
13
  type BundlerActions,
13
14
  type BundlerClientConfig,
14
15
  type PaymasterActions,
16
+ type PrepareUserOperationParameters,
15
17
  type SmartAccount,
16
18
  type UserOperationRequest,
17
- createBundlerClient
19
+ bundlerActions,
20
+ type prepareUserOperation as viemPrepareUserOperation
18
21
  } from "viem/account-abstraction"
19
22
  import {
20
23
  type SmartAccountActions,
@@ -101,6 +104,8 @@ export type SmartAccountClientConfig<
101
104
  userOperation: UserOperationRequest
102
105
  }) => Promise<EstimateFeesPerGasReturnType<"eip1559">>)
103
106
  | undefined
107
+ /** Prepare User Operation configuration. */
108
+ prepareUserOperation?: typeof viemPrepareUserOperation | undefined
104
109
  }
105
110
  | undefined
106
111
  }
@@ -134,17 +139,43 @@ export function createSmartAccountClient(
134
139
  userOperation
135
140
  } = parameters
136
141
 
137
- const client = createBundlerClient({
138
- ...parameters,
139
- client: client_,
140
- chain: parameters.chain ?? client_?.chain,
141
- key,
142
- name,
143
- transport: bundlerTransport,
144
- paymaster,
145
- paymasterContext,
146
- userOperation
147
- })
142
+ const client = Object.assign(
143
+ createClient({
144
+ ...parameters,
145
+ chain: parameters.chain ?? client_?.chain,
146
+ transport: bundlerTransport,
147
+ key,
148
+ name,
149
+ type: "bundlerClient" // TODO: is this okay?
150
+ }),
151
+ { client: client_, paymaster, paymasterContext, userOperation }
152
+ )
153
+
154
+ if (parameters.userOperation?.prepareUserOperation) {
155
+ const customPrepareUserOp =
156
+ parameters.userOperation.prepareUserOperation
157
+
158
+ return client
159
+ .extend(bundlerActions)
160
+ .extend((client) => ({
161
+ prepareUserOperation: (
162
+ args: PrepareUserOperationParameters
163
+ ) => {
164
+ return customPrepareUserOp(client, args)
165
+ }
166
+ }))
167
+ .extend(bundlerActions)
168
+ .extend((client) => ({
169
+ prepareUserOperation: (
170
+ args: PrepareUserOperationParameters
171
+ ) => {
172
+ return customPrepareUserOp(client, args)
173
+ }
174
+ }))
175
+ .extend(smartAccountActions()) as SmartAccountClient
176
+ }
148
177
 
149
- return client.extend(smartAccountActions()) as unknown as SmartAccountClient
178
+ return client
179
+ .extend(bundlerActions)
180
+ .extend(smartAccountActions()) as SmartAccountClient
150
181
  }
@@ -0,0 +1,2 @@
1
+ import { prepareUserOperationForErc20Paymaster } from "./utils/prepareUserOperationForErc20Paymaster"
2
+ export { prepareUserOperationForErc20Paymaster }
@@ -0,0 +1,195 @@
1
+ import { http, parseEther, zeroAddress } from "viem"
2
+ import {
3
+ entryPoint06Address,
4
+ entryPoint07Address
5
+ } from "viem/account-abstraction"
6
+ import { foundry } from "viem/chains"
7
+ import { describe, expect } from "vitest"
8
+ import {
9
+ ERC20_ADDRESS,
10
+ sudoMintTokens,
11
+ tokenBalanceOf
12
+ } from "../../../../permissionless-test/src/erc20-utils.ts"
13
+ import { testWithRpc } from "../../../../permissionless-test/src/testWithRpc.ts"
14
+ import {
15
+ getCoreSmartAccounts,
16
+ getPublicClient
17
+ } from "../../../../permissionless-test/src/utils"
18
+ import { createSmartAccountClient } from "../../../clients/createSmartAccountClient.ts"
19
+ import { createPimlicoClient } from "../../../clients/pimlico.ts"
20
+ import { prepareUserOperationForErc20Paymaster } from "./prepareUserOperationForErc20Paymaster.ts"
21
+
22
+ describe.each(getCoreSmartAccounts())(
23
+ "prepareUserOperationForErc20Paymaster $name",
24
+ ({
25
+ getSmartAccountClient,
26
+ supportsEntryPointV06,
27
+ supportsEntryPointV07
28
+ }) => {
29
+ testWithRpc.skipIf(!supportsEntryPointV06)(
30
+ "prepareUserOperationForErc20Paymaster_v06",
31
+ async ({ rpc }) => {
32
+ const { anvilRpc } = rpc
33
+
34
+ const account = (
35
+ await getSmartAccountClient({
36
+ entryPoint: {
37
+ version: "0.6"
38
+ },
39
+ ...rpc
40
+ })
41
+ ).account
42
+
43
+ const pimlicoClient = createPimlicoClient({
44
+ transport: http(rpc.paymasterRpc),
45
+ entryPoint: {
46
+ address: entryPoint06Address,
47
+ version: "0.6"
48
+ }
49
+ })
50
+
51
+ const publicClient = getPublicClient(anvilRpc)
52
+
53
+ const smartAccountClient = createSmartAccountClient({
54
+ // @ts-ignore
55
+ client: getPublicClient(anvilRpc),
56
+ account,
57
+ paymaster: pimlicoClient,
58
+ chain: foundry,
59
+ userOperation: {
60
+ prepareUserOperation:
61
+ prepareUserOperationForErc20Paymaster(pimlicoClient)
62
+ },
63
+ bundlerTransport: http(rpc.altoRpc)
64
+ })
65
+
66
+ const INITIAL_TOKEN_BALANCE = parseEther("100")
67
+ const INTIAL_ETH_BALANCE = await publicClient.getBalance({
68
+ address: smartAccountClient.account.address
69
+ })
70
+
71
+ sudoMintTokens({
72
+ amount: INITIAL_TOKEN_BALANCE,
73
+ to: smartAccountClient.account.address,
74
+ anvilRpc
75
+ })
76
+
77
+ const opHash = await smartAccountClient.sendUserOperation({
78
+ calls: [
79
+ {
80
+ to: zeroAddress,
81
+ data: "0x",
82
+ value: 0n
83
+ }
84
+ ],
85
+ paymasterContext: {
86
+ token: ERC20_ADDRESS
87
+ }
88
+ })
89
+
90
+ const receipt =
91
+ await smartAccountClient.waitForUserOperationReceipt({
92
+ hash: opHash
93
+ })
94
+
95
+ expect(receipt).toBeTruthy()
96
+ expect(receipt).toBeTruthy()
97
+ expect(receipt.success).toBeTruthy()
98
+
99
+ const FINAL_TOKEN_BALANCE = await tokenBalanceOf(
100
+ smartAccountClient.account.address,
101
+ rpc.anvilRpc
102
+ )
103
+ const FINAL_ETH_BALANCE = await publicClient.getBalance({
104
+ address: smartAccountClient.account.address
105
+ })
106
+
107
+ expect(FINAL_TOKEN_BALANCE).toBeLessThan(INITIAL_TOKEN_BALANCE) // Token balance should be deducted
108
+ expect(FINAL_ETH_BALANCE).toEqual(INTIAL_ETH_BALANCE) // There should be no ETH balance change
109
+ }
110
+ )
111
+
112
+ testWithRpc.skipIf(!supportsEntryPointV07)(
113
+ "prepareUserOperationForErc20Paymaster_v07",
114
+ async ({ rpc }) => {
115
+ const { anvilRpc } = rpc
116
+
117
+ const account = (
118
+ await getSmartAccountClient({
119
+ entryPoint: {
120
+ version: "0.7"
121
+ },
122
+ ...rpc
123
+ })
124
+ ).account
125
+
126
+ const publicClient = getPublicClient(anvilRpc)
127
+
128
+ const pimlicoClient = createPimlicoClient({
129
+ transport: http(rpc.paymasterRpc),
130
+ entryPoint: {
131
+ address: entryPoint07Address,
132
+ version: "0.7"
133
+ }
134
+ })
135
+
136
+ const smartAccountClient = createSmartAccountClient({
137
+ // @ts-ignore
138
+ client: getPublicClient(anvilRpc),
139
+ account,
140
+ paymaster: pimlicoClient,
141
+ chain: foundry,
142
+ userOperation: {
143
+ prepareUserOperation:
144
+ prepareUserOperationForErc20Paymaster(pimlicoClient)
145
+ },
146
+ bundlerTransport: http(rpc.altoRpc)
147
+ })
148
+
149
+ const INITIAL_TOKEN_BALANCE = parseEther("100")
150
+ const INTIAL_ETH_BALANCE = await publicClient.getBalance({
151
+ address: smartAccountClient.account.address
152
+ })
153
+
154
+ sudoMintTokens({
155
+ amount: INITIAL_TOKEN_BALANCE,
156
+ to: smartAccountClient.account.address,
157
+ anvilRpc
158
+ })
159
+
160
+ const opHash = await smartAccountClient.sendUserOperation({
161
+ calls: [
162
+ {
163
+ to: zeroAddress,
164
+ data: "0x",
165
+ value: 0n
166
+ }
167
+ ],
168
+ paymasterContext: {
169
+ token: ERC20_ADDRESS
170
+ }
171
+ })
172
+
173
+ const receipt =
174
+ await smartAccountClient.waitForUserOperationReceipt({
175
+ hash: opHash
176
+ })
177
+
178
+ expect(receipt).toBeTruthy()
179
+ expect(receipt).toBeTruthy()
180
+ expect(receipt.success).toBeTruthy()
181
+
182
+ const FINAL_TOKEN_BALANCE = await tokenBalanceOf(
183
+ smartAccountClient.account.address,
184
+ rpc.anvilRpc
185
+ )
186
+ const FINAL_ETH_BALANCE = await publicClient.getBalance({
187
+ address: smartAccountClient.account.address
188
+ })
189
+
190
+ expect(FINAL_TOKEN_BALANCE).toBeLessThan(INITIAL_TOKEN_BALANCE) // Token balance should be deducted
191
+ expect(FINAL_ETH_BALANCE).toEqual(INTIAL_ETH_BALANCE) // There should be no ETH balance change
192
+ }
193
+ )
194
+ }
195
+ )