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.
- package/CHANGELOG.md +12 -0
- package/_cjs/accounts/biconomy/toBiconomySmartAccount.js +37 -13
- package/_cjs/accounts/biconomy/toBiconomySmartAccount.js.map +1 -1
- package/_cjs/accounts/kernel/toEcdsaKernelSmartAccount.js +2 -2
- package/_cjs/accounts/kernel/toEcdsaKernelSmartAccount.js.map +1 -1
- package/_cjs/accounts/kernel/utils/signMessage.js +1 -2
- package/_cjs/accounts/kernel/utils/signMessage.js.map +1 -1
- package/_cjs/accounts/kernel/utils/signTypedData.js +1 -2
- package/_cjs/accounts/kernel/utils/signTypedData.js.map +1 -1
- package/_cjs/accounts/light/toLightSmartAccount.js +1 -2
- package/_cjs/accounts/light/toLightSmartAccount.js.map +1 -1
- package/_cjs/accounts/safe/toSafeSmartAccount.js +1 -2
- package/_cjs/accounts/safe/toSafeSmartAccount.js.map +1 -1
- package/_cjs/accounts/simple/toSimpleSmartAccount.js +1 -2
- package/_cjs/accounts/simple/toSimpleSmartAccount.js.map +1 -1
- package/_cjs/accounts/trust/toTrustSmartAccount.js +2 -2
- package/_cjs/accounts/trust/toTrustSmartAccount.js.map +1 -1
- package/_cjs/actions/erc7579/accountId.js +1 -2
- package/_cjs/actions/erc7579/accountId.js.map +1 -1
- package/_cjs/actions/erc7579/installModule.js +1 -2
- package/_cjs/actions/erc7579/installModule.js.map +1 -1
- package/_cjs/actions/erc7579/installModules.js +1 -2
- package/_cjs/actions/erc7579/installModules.js.map +1 -1
- package/_cjs/actions/erc7579/isModuleInstalled.js +1 -2
- package/_cjs/actions/erc7579/isModuleInstalled.js.map +1 -1
- package/_cjs/actions/erc7579/supportsExecutionMode.js +2 -3
- package/_cjs/actions/erc7579/supportsExecutionMode.js.map +1 -1
- package/_cjs/actions/erc7579/supportsModule.js +2 -3
- package/_cjs/actions/erc7579/supportsModule.js.map +1 -1
- package/_cjs/actions/erc7579/uninstallModule.js +1 -2
- package/_cjs/actions/erc7579/uninstallModule.js.map +1 -1
- package/_cjs/actions/erc7579/uninstallModules.js +1 -2
- package/_cjs/actions/erc7579/uninstallModules.js.map +1 -1
- package/_cjs/actions/erc7579.js +2 -2
- package/_cjs/actions/erc7579.js.map +1 -1
- package/_cjs/actions/smartAccount/sendTransaction.js +1 -2
- package/_cjs/actions/smartAccount/sendTransaction.js.map +1 -1
- package/_cjs/actions/smartAccount/signMessage.js +1 -2
- package/_cjs/actions/smartAccount/signMessage.js.map +1 -1
- package/_cjs/actions/smartAccount/signTypedData.js +1 -2
- package/_cjs/actions/smartAccount/signTypedData.js.map +1 -1
- package/_cjs/actions/smartAccount/writeContract.js +1 -2
- package/_cjs/actions/smartAccount/writeContract.js.map +1 -1
- package/_cjs/clients/createSmartAccountClient.js +26 -10
- package/_cjs/clients/createSmartAccountClient.js.map +1 -1
- package/_cjs/clients/decorators/smartAccount.js +1 -2
- package/_cjs/clients/decorators/smartAccount.js.map +1 -1
- package/_cjs/clients/pimlico.js +1 -2
- package/_cjs/clients/pimlico.js.map +1 -1
- package/_cjs/experimental/pimlico/index.js +6 -0
- package/_cjs/experimental/pimlico/index.js.map +1 -0
- package/_cjs/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.js +126 -0
- package/_cjs/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.js.map +1 -0
- package/_cjs/utils/decodeNonce.js +1 -2
- package/_cjs/utils/decodeNonce.js.map +1 -1
- package/_cjs/utils/deepHexlify.js +2 -2
- package/_cjs/utils/deepHexlify.js.map +1 -1
- package/_cjs/utils/encode7579Calls.js +1 -2
- package/_cjs/utils/encode7579Calls.js.map +1 -1
- package/_cjs/utils/encodeInstallModule.js +1 -2
- package/_cjs/utils/encodeInstallModule.js.map +1 -1
- package/_cjs/utils/encodeNonce.js +1 -2
- package/_cjs/utils/encodeNonce.js.map +1 -1
- package/_cjs/utils/encodeUninstallModule.js +1 -2
- package/_cjs/utils/encodeUninstallModule.js.map +1 -1
- package/_cjs/utils/getAddressFromInitCodeOrPaymasterAndData.js +1 -2
- package/_cjs/utils/getAddressFromInitCodeOrPaymasterAndData.js.map +1 -1
- package/_cjs/utils/getPackedUserOperation.js +9 -9
- package/_cjs/utils/getPackedUserOperation.js.map +1 -1
- package/_cjs/utils/toOwner.js +1 -2
- package/_cjs/utils/toOwner.js.map +1 -1
- package/_esm/accounts/biconomy/toBiconomySmartAccount.js +39 -12
- package/_esm/accounts/biconomy/toBiconomySmartAccount.js.map +1 -1
- package/_esm/accounts/safe/toSafeSmartAccount.js.map +1 -1
- package/_esm/clients/createSmartAccountClient.js +26 -9
- package/_esm/clients/createSmartAccountClient.js.map +1 -1
- package/_esm/experimental/pimlico/index.js +3 -0
- package/_esm/experimental/pimlico/index.js.map +1 -0
- package/_esm/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.js +144 -0
- package/_esm/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.js.map +1 -0
- package/_types/accounts/biconomy/toBiconomySmartAccount.d.ts +2 -0
- package/_types/accounts/biconomy/toBiconomySmartAccount.d.ts.map +1 -1
- package/_types/accounts/kernel/utils/encodeCallData.d.ts.map +1 -1
- package/_types/accounts/kernel/utils/getNonceKey.d.ts.map +1 -1
- package/_types/accounts/kernel/utils/isKernelV2.d.ts.map +1 -1
- package/_types/accounts/safe/toSafeSmartAccount.d.ts +0 -1
- package/_types/accounts/safe/toSafeSmartAccount.d.ts.map +1 -1
- package/_types/actions/erc7579.d.ts +1 -249
- package/_types/actions/erc7579.d.ts.map +1 -1
- package/_types/actions/pimlico/getTokenQuotes.d.ts.map +1 -1
- package/_types/actions/pimlico/getUserOperationGasPrice.d.ts.map +1 -1
- package/_types/actions/pimlico/getUserOperationStatus.d.ts.map +1 -1
- package/_types/actions/pimlico/sendCompressedUserOperation.d.ts.map +1 -1
- package/_types/actions/pimlico/sponsorUserOperation.d.ts.map +1 -1
- package/_types/actions/pimlico/validateSponsorshipPolicies.d.ts.map +1 -1
- package/_types/actions/public/getAccountNonce.d.ts.map +1 -1
- package/_types/actions/public/getSenderAddress.d.ts.map +1 -1
- package/_types/clients/createSmartAccountClient.d.ts +4 -2
- package/_types/clients/createSmartAccountClient.d.ts.map +1 -1
- package/_types/clients/decorators/pimlico.d.ts.map +1 -1
- package/_types/clients/decorators/smartAccount.d.ts +16 -471
- package/_types/clients/decorators/smartAccount.d.ts.map +1 -1
- package/_types/experimental/pimlico/index.d.ts +3 -0
- package/_types/experimental/pimlico/index.d.ts.map +1 -0
- package/_types/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.d.ts +4 -0
- package/_types/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.d.ts.map +1 -0
- package/_types/utils/getPackedUserOperation.d.ts.map +1 -1
- package/_types/utils/getRequiredPrefund.d.ts.map +1 -1
- package/_types/utils/isSmartAccountDeployed.d.ts.map +1 -1
- package/accounts/biconomy/toBiconomySmartAccount.ts +85 -16
- package/accounts/safe/toSafeSmartAccount.ts +0 -1
- package/actions/smartAccount/sendTransaction.test.ts +129 -0
- package/clients/createSmartAccountClient.ts +53 -22
- package/experimental/pimlico/index.ts +2 -0
- package/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.test.ts +195 -0
- package/experimental/pimlico/utils/prepareUserOperationForErc20Paymaster.ts +270 -0
- 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 {
|
|
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
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
|
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
|
-
|
|
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 =
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
|
178
|
+
return client
|
|
179
|
+
.extend(bundlerActions)
|
|
180
|
+
.extend(smartAccountActions()) as SmartAccountClient
|
|
150
181
|
}
|
|
@@ -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
|
+
)
|