thirdweb 5.48.2 → 5.48.3-nightly-a8e2bc58c9e8fe5b75d6c27d406e6b80d5d067e2-20240828000339

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 (176) hide show
  1. package/dist/cjs/exports/wallets/smart.js +4 -2
  2. package/dist/cjs/exports/wallets/smart.js.map +1 -1
  3. package/dist/cjs/extensions/erc1155/drops/write/claimTo.js.map +1 -1
  4. package/dist/cjs/extensions/erc4337/__generated__/IEntryPoint_v07/events/PostOpRevertReason.js +32 -0
  5. package/dist/cjs/extensions/erc4337/__generated__/IEntryPoint_v07/events/PostOpRevertReason.js.map +1 -0
  6. package/dist/cjs/extensions/erc4337/__generated__/IEntryPoint_v07/read/getUserOpHash.js +153 -0
  7. package/dist/cjs/extensions/erc4337/__generated__/IEntryPoint_v07/read/getUserOpHash.js.map +1 -0
  8. package/dist/cjs/extensions/prebuilts/__generated__/VoteERC20/write/initialize.js +184 -0
  9. package/dist/cjs/extensions/prebuilts/__generated__/VoteERC20/write/initialize.js.map +1 -0
  10. package/dist/cjs/extensions/prebuilts/deploy-vote.js +122 -0
  11. package/dist/cjs/extensions/prebuilts/deploy-vote.js.map +1 -0
  12. package/dist/cjs/react/core/hooks/pay/useBuyWithCryptoQuote.js +5 -1
  13. package/dist/cjs/react/core/hooks/pay/useBuyWithCryptoQuote.js.map +1 -1
  14. package/dist/cjs/react/core/hooks/pay/useBuyWithFiatQuote.js +5 -1
  15. package/dist/cjs/react/core/hooks/pay/useBuyWithFiatQuote.js.map +1 -1
  16. package/dist/cjs/react/core/hooks/transaction/useSendAndConfirmTransaction.js +12 -0
  17. package/dist/cjs/react/core/hooks/transaction/useSendAndConfirmTransaction.js.map +1 -1
  18. package/dist/cjs/react/native/hooks/transaction/useSendTransaction.js +11 -0
  19. package/dist/cjs/react/native/hooks/transaction/useSendTransaction.js.map +1 -1
  20. package/dist/cjs/react/web/ui/TransactionButton/index.js +13 -0
  21. package/dist/cjs/react/web/ui/TransactionButton/index.js.map +1 -1
  22. package/dist/cjs/transaction/actions/send-and-confirm-transaction.js +13 -0
  23. package/dist/cjs/transaction/actions/send-and-confirm-transaction.js.map +1 -1
  24. package/dist/cjs/transaction/actions/send-transaction.js +13 -0
  25. package/dist/cjs/transaction/actions/send-transaction.js.map +1 -1
  26. package/dist/cjs/transaction/actions/zksync/send-eip712-transaction.js +1 -1
  27. package/dist/cjs/transaction/actions/zksync/send-eip712-transaction.js.map +1 -1
  28. package/dist/cjs/version.js +1 -1
  29. package/dist/cjs/version.js.map +1 -1
  30. package/dist/cjs/wallets/in-app/web/lib/in-app-account.js +5 -1
  31. package/dist/cjs/wallets/in-app/web/lib/in-app-account.js.map +1 -1
  32. package/dist/cjs/wallets/in-app/web/utils/iFrameCommunication/IframeCommunicator.js +1 -0
  33. package/dist/cjs/wallets/in-app/web/utils/iFrameCommunication/IframeCommunicator.js.map +1 -1
  34. package/dist/cjs/wallets/smart/index.js +13 -2
  35. package/dist/cjs/wallets/smart/index.js.map +1 -1
  36. package/dist/cjs/wallets/smart/lib/bundler.js +11 -2
  37. package/dist/cjs/wallets/smart/lib/bundler.js.map +1 -1
  38. package/dist/cjs/wallets/smart/lib/constants.js +27 -13
  39. package/dist/cjs/wallets/smart/lib/constants.js.map +1 -1
  40. package/dist/cjs/wallets/smart/lib/packUserOp.js +75 -0
  41. package/dist/cjs/wallets/smart/lib/packUserOp.js.map +1 -0
  42. package/dist/cjs/wallets/smart/lib/paymaster.js +11 -1
  43. package/dist/cjs/wallets/smart/lib/paymaster.js.map +1 -1
  44. package/dist/cjs/wallets/smart/lib/userop.js +201 -66
  45. package/dist/cjs/wallets/smart/lib/userop.js.map +1 -1
  46. package/dist/cjs/wallets/smart/lib/utils.js +1 -1
  47. package/dist/cjs/wallets/smart/lib/utils.js.map +1 -1
  48. package/dist/cjs/wallets/smart/smart-wallet.js +2 -1
  49. package/dist/cjs/wallets/smart/smart-wallet.js.map +1 -1
  50. package/dist/cjs/wallets/smart/types.js.map +1 -1
  51. package/dist/esm/exports/wallets/smart.js +1 -1
  52. package/dist/esm/exports/wallets/smart.js.map +1 -1
  53. package/dist/esm/extensions/erc1155/drops/write/claimTo.js.map +1 -1
  54. package/dist/esm/extensions/erc4337/__generated__/IEntryPoint_v07/events/PostOpRevertReason.js +29 -0
  55. package/dist/esm/extensions/erc4337/__generated__/IEntryPoint_v07/events/PostOpRevertReason.js.map +1 -0
  56. package/dist/esm/extensions/erc4337/__generated__/IEntryPoint_v07/read/getUserOpHash.js +145 -0
  57. package/dist/esm/extensions/erc4337/__generated__/IEntryPoint_v07/read/getUserOpHash.js.map +1 -0
  58. package/dist/esm/extensions/prebuilts/__generated__/VoteERC20/write/initialize.js +177 -0
  59. package/dist/esm/extensions/prebuilts/__generated__/VoteERC20/write/initialize.js.map +1 -0
  60. package/dist/esm/extensions/prebuilts/deploy-vote.js +119 -0
  61. package/dist/esm/extensions/prebuilts/deploy-vote.js.map +1 -0
  62. package/dist/esm/react/core/hooks/pay/useBuyWithCryptoQuote.js +5 -1
  63. package/dist/esm/react/core/hooks/pay/useBuyWithCryptoQuote.js.map +1 -1
  64. package/dist/esm/react/core/hooks/pay/useBuyWithFiatQuote.js +5 -1
  65. package/dist/esm/react/core/hooks/pay/useBuyWithFiatQuote.js.map +1 -1
  66. package/dist/esm/react/core/hooks/transaction/useSendAndConfirmTransaction.js +12 -0
  67. package/dist/esm/react/core/hooks/transaction/useSendAndConfirmTransaction.js.map +1 -1
  68. package/dist/esm/react/native/hooks/transaction/useSendTransaction.js +11 -0
  69. package/dist/esm/react/native/hooks/transaction/useSendTransaction.js.map +1 -1
  70. package/dist/esm/react/web/ui/TransactionButton/index.js +13 -0
  71. package/dist/esm/react/web/ui/TransactionButton/index.js.map +1 -1
  72. package/dist/esm/transaction/actions/send-and-confirm-transaction.js +13 -0
  73. package/dist/esm/transaction/actions/send-and-confirm-transaction.js.map +1 -1
  74. package/dist/esm/transaction/actions/send-transaction.js +13 -0
  75. package/dist/esm/transaction/actions/send-transaction.js.map +1 -1
  76. package/dist/esm/transaction/actions/zksync/send-eip712-transaction.js +1 -1
  77. package/dist/esm/transaction/actions/zksync/send-eip712-transaction.js.map +1 -1
  78. package/dist/esm/version.js +1 -1
  79. package/dist/esm/version.js.map +1 -1
  80. package/dist/esm/wallets/in-app/web/lib/in-app-account.js +5 -1
  81. package/dist/esm/wallets/in-app/web/lib/in-app-account.js.map +1 -1
  82. package/dist/esm/wallets/in-app/web/utils/iFrameCommunication/IframeCommunicator.js +1 -0
  83. package/dist/esm/wallets/in-app/web/utils/iFrameCommunication/IframeCommunicator.js.map +1 -1
  84. package/dist/esm/wallets/smart/index.js +14 -3
  85. package/dist/esm/wallets/smart/index.js.map +1 -1
  86. package/dist/esm/wallets/smart/lib/bundler.js +12 -3
  87. package/dist/esm/wallets/smart/lib/bundler.js.map +1 -1
  88. package/dist/esm/wallets/smart/lib/constants.js +23 -10
  89. package/dist/esm/wallets/smart/lib/constants.js.map +1 -1
  90. package/dist/esm/wallets/smart/lib/packUserOp.js +65 -0
  91. package/dist/esm/wallets/smart/lib/packUserOp.js.map +1 -0
  92. package/dist/esm/wallets/smart/lib/paymaster.js +12 -2
  93. package/dist/esm/wallets/smart/lib/paymaster.js.map +1 -1
  94. package/dist/esm/wallets/smart/lib/userop.js +202 -67
  95. package/dist/esm/wallets/smart/lib/userop.js.map +1 -1
  96. package/dist/esm/wallets/smart/lib/utils.js +1 -1
  97. package/dist/esm/wallets/smart/lib/utils.js.map +1 -1
  98. package/dist/esm/wallets/smart/smart-wallet.js +3 -2
  99. package/dist/esm/wallets/smart/smart-wallet.js.map +1 -1
  100. package/dist/esm/wallets/smart/types.js.map +1 -1
  101. package/dist/types/exports/wallets/smart.d.ts +2 -2
  102. package/dist/types/exports/wallets/smart.d.ts.map +1 -1
  103. package/dist/types/extensions/erc1155/drops/write/claimTo.d.ts +2 -3
  104. package/dist/types/extensions/erc1155/drops/write/claimTo.d.ts.map +1 -1
  105. package/dist/types/extensions/erc4337/__generated__/IEntryPoint_v07/events/PostOpRevertReason.d.ts +57 -0
  106. package/dist/types/extensions/erc4337/__generated__/IEntryPoint_v07/events/PostOpRevertReason.d.ts.map +1 -0
  107. package/dist/types/extensions/erc4337/__generated__/IEntryPoint_v07/read/getUserOpHash.d.ts +123 -0
  108. package/dist/types/extensions/erc4337/__generated__/IEntryPoint_v07/read/getUserOpHash.d.ts.map +1 -0
  109. package/dist/types/extensions/prebuilts/__generated__/VoteERC20/write/initialize.d.ts +129 -0
  110. package/dist/types/extensions/prebuilts/__generated__/VoteERC20/write/initialize.d.ts.map +1 -0
  111. package/dist/types/extensions/prebuilts/deploy-vote.d.ts +82 -0
  112. package/dist/types/extensions/prebuilts/deploy-vote.d.ts.map +1 -0
  113. package/dist/types/react/core/hooks/pay/useBuyWithCryptoQuote.d.ts.map +1 -1
  114. package/dist/types/react/core/hooks/pay/useBuyWithFiatQuote.d.ts.map +1 -1
  115. package/dist/types/react/core/hooks/transaction/useSendAndConfirmTransaction.d.ts +12 -0
  116. package/dist/types/react/core/hooks/transaction/useSendAndConfirmTransaction.d.ts.map +1 -1
  117. package/dist/types/react/native/hooks/transaction/useSendTransaction.d.ts +11 -0
  118. package/dist/types/react/native/hooks/transaction/useSendTransaction.d.ts.map +1 -1
  119. package/dist/types/react/web/ui/TransactionButton/index.d.ts +13 -0
  120. package/dist/types/react/web/ui/TransactionButton/index.d.ts.map +1 -1
  121. package/dist/types/transaction/actions/send-and-confirm-transaction.d.ts +13 -0
  122. package/dist/types/transaction/actions/send-and-confirm-transaction.d.ts.map +1 -1
  123. package/dist/types/transaction/actions/send-transaction.d.ts +13 -0
  124. package/dist/types/transaction/actions/send-transaction.d.ts.map +1 -1
  125. package/dist/types/version.d.ts +1 -1
  126. package/dist/types/version.d.ts.map +1 -1
  127. package/dist/types/wallets/in-app/web/lib/in-app-account.d.ts.map +1 -1
  128. package/dist/types/wallets/in-app/web/utils/iFrameCommunication/IframeCommunicator.d.ts.map +1 -1
  129. package/dist/types/wallets/smart/index.d.ts.map +1 -1
  130. package/dist/types/wallets/smart/lib/bundler.d.ts +3 -3
  131. package/dist/types/wallets/smart/lib/bundler.d.ts.map +1 -1
  132. package/dist/types/wallets/smart/lib/constants.d.ts +6 -6
  133. package/dist/types/wallets/smart/lib/constants.d.ts.map +1 -1
  134. package/dist/types/wallets/smart/lib/packUserOp.d.ts +16 -0
  135. package/dist/types/wallets/smart/lib/packUserOp.d.ts.map +1 -0
  136. package/dist/types/wallets/smart/lib/paymaster.d.ts +3 -3
  137. package/dist/types/wallets/smart/lib/paymaster.d.ts.map +1 -1
  138. package/dist/types/wallets/smart/lib/userop.d.ts +6 -4
  139. package/dist/types/wallets/smart/lib/userop.d.ts.map +1 -1
  140. package/dist/types/wallets/smart/lib/utils.d.ts +2 -2
  141. package/dist/types/wallets/smart/lib/utils.d.ts.map +1 -1
  142. package/dist/types/wallets/smart/smart-wallet.d.ts.map +1 -1
  143. package/dist/types/wallets/smart/types.d.ts +62 -9
  144. package/dist/types/wallets/smart/types.d.ts.map +1 -1
  145. package/package.json +1 -1
  146. package/src/exports/wallets/smart.ts +4 -2
  147. package/src/extensions/erc1155/drops/write/claimTo.ts +2 -3
  148. package/src/extensions/erc4337/__generated__/IEntryPoint_v07/events/PostOpRevertReason.ts +49 -0
  149. package/src/extensions/erc4337/__generated__/IEntryPoint_v07/read/getUserOpHash.ts +181 -0
  150. package/src/extensions/prebuilts/__generated__/VoteERC20/write/initialize.ts +230 -0
  151. package/src/extensions/prebuilts/deploy-vote.test.ts +73 -0
  152. package/src/extensions/prebuilts/deploy-vote.ts +213 -0
  153. package/src/extensions/vote/read/proposalExists.test.ts +123 -0
  154. package/src/react/core/hooks/pay/useBuyWithCryptoQuote.ts +16 -1
  155. package/src/react/core/hooks/pay/useBuyWithFiatQuote.ts +16 -1
  156. package/src/react/core/hooks/transaction/useSendAndConfirmTransaction.ts +12 -0
  157. package/src/react/native/hooks/transaction/useSendTransaction.tsx +11 -0
  158. package/src/react/web/ui/TransactionButton/index.tsx +13 -0
  159. package/src/transaction/actions/send-and-confirm-transaction.ts +13 -0
  160. package/src/transaction/actions/send-transaction.ts +13 -0
  161. package/src/transaction/actions/zksync/send-eip712-transaction.ts +1 -1
  162. package/src/version.ts +1 -1
  163. package/src/wallets/in-app/web/lib/in-app-account.ts +5 -1
  164. package/src/wallets/in-app/web/utils/iFrameCommunication/IframeCommunicator.ts +1 -0
  165. package/src/wallets/smart/index.ts +21 -5
  166. package/src/wallets/smart/lib/bundler.ts +21 -5
  167. package/src/wallets/smart/lib/constants.ts +29 -10
  168. package/src/wallets/smart/lib/packUserOp.ts +79 -0
  169. package/src/wallets/smart/lib/paymaster.ts +22 -5
  170. package/src/wallets/smart/lib/userop.ts +292 -85
  171. package/src/wallets/smart/lib/utils.ts +11 -4
  172. package/src/wallets/smart/smart-wallet-integration-v07.test.ts +206 -0
  173. package/src/wallets/smart/smart-wallet-integration.test.ts +1 -1
  174. package/src/wallets/smart/smart-wallet-zksync.test.ts +3 -3
  175. package/src/wallets/smart/smart-wallet.ts +4 -2
  176. package/src/wallets/smart/types.ts +73 -9
@@ -6,22 +6,24 @@ import {
6
6
  getContract,
7
7
  } from "../../../contract/contract.js";
8
8
  import { getNonce } from "../../../extensions/erc4337/__generated__/IEntryPoint/read/getNonce.js";
9
+ import { getUserOpHash as getUserOpHashV06 } from "../../../extensions/erc4337/__generated__/IEntryPoint/read/getUserOpHash.js";
10
+ import { getUserOpHash as getUserOpHashV07 } from "../../../extensions/erc4337/__generated__/IEntryPoint_v07/read/getUserOpHash.js";
9
11
  import { getDefaultGasOverrides } from "../../../gas/fee-data.js";
10
12
  import { encode } from "../../../transaction/actions/encode.js";
11
13
  import type { PreparedTransaction } from "../../../transaction/prepare-transaction.js";
12
14
  import type { TransactionReceipt } from "../../../transaction/types.js";
13
- import { encodeAbiParameters } from "../../../utils/abi/encodeAbiParameters.js";
14
15
  import { isContractDeployed } from "../../../utils/bytecode/is-contract-deployed.js";
15
16
  import type { Hex } from "../../../utils/encoding/hex.js";
16
17
  import { hexToBytes } from "../../../utils/encoding/to-bytes.js";
17
18
  import { isThirdwebUrl } from "../../../utils/fetch.js";
18
- import { keccak256 } from "../../../utils/hashing/keccak256.js";
19
19
  import { resolvePromisedValue } from "../../../utils/promise/resolve-promised-value.js";
20
20
  import type { Account } from "../../interfaces/wallet.js";
21
21
  import type {
22
22
  BundlerOptions,
23
+ PaymasterResult,
23
24
  SmartWalletOptions,
24
- UserOperation,
25
+ UserOperationV06,
26
+ UserOperationV07,
25
27
  } from "../types.js";
26
28
  import {
27
29
  estimateUserOpGas,
@@ -32,8 +34,11 @@ import { prepareCreateAccount } from "./calls.js";
32
34
  import {
33
35
  DUMMY_SIGNATURE,
34
36
  ENTRYPOINT_ADDRESS_v0_6,
37
+ ENTRYPOINT_ADDRESS_v0_7,
35
38
  getDefaultBundlerUrl,
39
+ getEntryPointVersion,
36
40
  } from "./constants.js";
41
+ import { getPackedUserOperation } from "./packUserOp.js";
37
42
  import { getPaymasterAndData } from "./paymaster.js";
38
43
  import { generateRandomUint192 } from "./utils.js";
39
44
 
@@ -102,7 +107,7 @@ export async function createUnsignedUserOp(args: {
102
107
  adminAddress: string;
103
108
  sponsorGas: boolean;
104
109
  overrides?: SmartWalletOptions["overrides"];
105
- }): Promise<UserOperation> {
110
+ }): Promise<UserOperationV06 | UserOperationV07> {
106
111
  const {
107
112
  transaction: executeTx,
108
113
  accountContract,
@@ -113,24 +118,88 @@ export async function createUnsignedUserOp(args: {
113
118
  } = args;
114
119
  const chain = executeTx.chain;
115
120
  const client = executeTx.client;
116
- const isDeployed = await isContractDeployed(accountContract);
117
- const initCode = isDeployed
118
- ? "0x"
119
- : await getAccountInitCode({
120
- factoryContract: factoryContract,
121
- adminAddress,
122
- accountSalt: overrides?.accountSalt,
123
- createAccountOverride: overrides?.createAccount,
124
- });
125
- const callData = await encode(executeTx);
121
+
126
122
  const bundlerOptions = {
127
123
  client,
128
124
  chain,
129
125
  entrypointAddress: overrides?.entrypointAddress,
130
126
  };
131
127
 
128
+ const entrypointVersion = getEntryPointVersion(
129
+ args.overrides?.entrypointAddress || ENTRYPOINT_ADDRESS_v0_6,
130
+ );
131
+
132
+ const [isDeployed, callData, gasFees, nonce] = await Promise.all([
133
+ isContractDeployed(accountContract),
134
+ encode(executeTx),
135
+ getGasFees({
136
+ executeTx,
137
+ bundlerOptions,
138
+ chain,
139
+ client,
140
+ }),
141
+ getAccountNonce({
142
+ accountContract,
143
+ chain,
144
+ client,
145
+ entrypointAddress: overrides?.entrypointAddress,
146
+ getNonceOverride: overrides?.getAccountNonce,
147
+ }),
148
+ ]);
149
+
150
+ const { maxFeePerGas, maxPriorityFeePerGas } = gasFees;
151
+
152
+ if (entrypointVersion === "v0.7") {
153
+ return populateUserOp_v0_7({
154
+ bundlerOptions,
155
+ factoryContract,
156
+ accountContract,
157
+ adminAddress,
158
+ sponsorGas,
159
+ overrides,
160
+ isDeployed,
161
+ nonce,
162
+ callData,
163
+ maxFeePerGas,
164
+ maxPriorityFeePerGas,
165
+ });
166
+ }
167
+
168
+ // default to v0.6
169
+ return populateUserOp_v0_6({
170
+ bundlerOptions,
171
+ factoryContract,
172
+ accountContract,
173
+ adminAddress,
174
+ sponsorGas,
175
+ overrides,
176
+ isDeployed,
177
+ nonce,
178
+ callData,
179
+ maxFeePerGas,
180
+ maxPriorityFeePerGas,
181
+ });
182
+ }
183
+
184
+ async function getGasFees(args: {
185
+ executeTx: PreparedTransaction;
186
+ bundlerOptions: BundlerOptions;
187
+ chain: Chain;
188
+ client: ThirdwebClient;
189
+ }): Promise<{
190
+ maxFeePerGas: bigint;
191
+ maxPriorityFeePerGas: bigint;
192
+ }> {
193
+ const { executeTx, bundlerOptions, chain, client } = args;
132
194
  let { maxFeePerGas, maxPriorityFeePerGas } = executeTx;
133
- const bundlerUrl = overrides?.bundlerUrl ?? getDefaultBundlerUrl(chain);
195
+
196
+ const entrypointVersion = getEntryPointVersion(
197
+ bundlerOptions.entrypointAddress || ENTRYPOINT_ADDRESS_v0_6,
198
+ );
199
+ const bundlerVersion = entrypointVersion === "v0.6" ? "v1" : "v2";
200
+ const bundlerUrl =
201
+ bundlerOptions?.bundlerUrl ?? getDefaultBundlerUrl(chain, bundlerVersion);
202
+
134
203
  if (isThirdwebUrl(bundlerUrl)) {
135
204
  // get gas prices from bundler
136
205
  const bundlerGasPrice = await getUserOpGasFees({
@@ -160,16 +229,175 @@ export async function createUnsignedUserOp(args: {
160
229
  maxFeePerGas = resolvedMaxFeePerGas ?? feeData.maxFeePerGas ?? 0n;
161
230
  }
162
231
  }
232
+ return { maxFeePerGas, maxPriorityFeePerGas };
233
+ }
163
234
 
164
- const nonce = await getAccountNonce({
235
+ async function populateUserOp_v0_7(args: {
236
+ bundlerOptions: BundlerOptions;
237
+ factoryContract: ThirdwebContract;
238
+ accountContract: ThirdwebContract;
239
+ adminAddress: string;
240
+ sponsorGas: boolean;
241
+ overrides?: SmartWalletOptions["overrides"];
242
+ isDeployed: boolean;
243
+ nonce: bigint;
244
+ callData: Hex;
245
+ maxFeePerGas: bigint;
246
+ maxPriorityFeePerGas: bigint;
247
+ }): Promise<UserOperationV07> {
248
+ const {
249
+ bundlerOptions,
250
+ isDeployed,
251
+ factoryContract,
165
252
  accountContract,
166
- chain,
167
- client,
168
- entrypointAddress: overrides?.entrypointAddress,
169
- getNonceOverride: overrides?.getAccountNonce,
170
- });
253
+ adminAddress,
254
+ sponsorGas,
255
+ overrides,
256
+ nonce,
257
+ callData,
258
+ maxFeePerGas,
259
+ maxPriorityFeePerGas,
260
+ } = args;
261
+ const { chain, client } = bundlerOptions;
262
+ const factory = isDeployed ? undefined : factoryContract.address;
263
+ const factoryData = isDeployed
264
+ ? "0x"
265
+ : await encode(
266
+ prepareCreateAccount({
267
+ factoryContract: factoryContract,
268
+ adminAddress,
269
+ accountSalt: overrides?.accountSalt,
270
+ createAccountOverride: overrides?.createAccount,
271
+ }),
272
+ );
171
273
 
172
- const partialOp: UserOperation = {
274
+ const partialOp: UserOperationV07 = {
275
+ sender: accountContract.address,
276
+ nonce,
277
+ callData,
278
+ maxFeePerGas,
279
+ maxPriorityFeePerGas,
280
+ callGasLimit: 0n,
281
+ verificationGasLimit: 0n,
282
+ preVerificationGas: 0n,
283
+ factory,
284
+ factoryData,
285
+ paymaster: undefined,
286
+ paymasterData: "0x",
287
+ paymasterVerificationGasLimit: 0n,
288
+ paymasterPostOpGasLimit: 0n,
289
+ signature: DUMMY_SIGNATURE,
290
+ };
291
+
292
+ if (sponsorGas) {
293
+ const paymasterResult = (await getPaymasterAndData({
294
+ userOp: partialOp,
295
+ chain,
296
+ client,
297
+ entrypointAddress: overrides?.entrypointAddress,
298
+ paymasterOverride: overrides?.paymaster,
299
+ })) as Extract<PaymasterResult, { paymaster: string }>;
300
+ if (paymasterResult.paymaster && paymasterResult.paymasterData) {
301
+ partialOp.paymaster = paymasterResult.paymaster;
302
+ partialOp.paymasterData = paymasterResult.paymasterData as Hex;
303
+ }
304
+ // paymaster can have the gas limits in the response
305
+ if (
306
+ paymasterResult.callGasLimit &&
307
+ paymasterResult.verificationGasLimit &&
308
+ paymasterResult.preVerificationGas &&
309
+ paymasterResult.paymasterPostOpGasLimit &&
310
+ paymasterResult.paymasterVerificationGasLimit
311
+ ) {
312
+ partialOp.callGasLimit = paymasterResult.callGasLimit;
313
+ partialOp.verificationGasLimit = paymasterResult.verificationGasLimit;
314
+ partialOp.preVerificationGas = paymasterResult.preVerificationGas;
315
+ partialOp.paymasterPostOpGasLimit =
316
+ paymasterResult.paymasterPostOpGasLimit;
317
+ partialOp.paymasterVerificationGasLimit =
318
+ paymasterResult.paymasterVerificationGasLimit;
319
+ } else {
320
+ // otherwise fallback to bundler for gas limits
321
+ const estimates = await estimateUserOpGas({
322
+ userOp: partialOp,
323
+ options: bundlerOptions,
324
+ });
325
+ partialOp.callGasLimit = estimates.callGasLimit;
326
+ partialOp.verificationGasLimit = estimates.verificationGasLimit;
327
+ partialOp.preVerificationGas = estimates.preVerificationGas;
328
+ partialOp.paymasterPostOpGasLimit =
329
+ paymasterResult.paymasterPostOpGasLimit || 0n;
330
+ partialOp.paymasterVerificationGasLimit =
331
+ paymasterResult.paymasterVerificationGasLimit || 0n;
332
+ // need paymaster to re-sign after estimates
333
+ const paymasterResult2 = (await getPaymasterAndData({
334
+ userOp: partialOp,
335
+ chain,
336
+ client,
337
+ entrypointAddress: overrides?.entrypointAddress,
338
+ paymasterOverride: overrides?.paymaster,
339
+ })) as Extract<PaymasterResult, { paymaster: string }>;
340
+ if (paymasterResult2.paymaster && paymasterResult2.paymasterData) {
341
+ partialOp.paymaster = paymasterResult2.paymaster;
342
+ partialOp.paymasterData = paymasterResult2.paymasterData as Hex;
343
+ }
344
+ }
345
+ } else {
346
+ // not gasless, so we just need to estimate gas limits
347
+ const estimates = await estimateUserOpGas({
348
+ userOp: partialOp,
349
+ options: bundlerOptions,
350
+ });
351
+ partialOp.callGasLimit = estimates.callGasLimit;
352
+ partialOp.verificationGasLimit = estimates.verificationGasLimit;
353
+ partialOp.preVerificationGas = estimates.preVerificationGas;
354
+ partialOp.paymasterPostOpGasLimit = estimates.paymasterPostOpGasLimit || 0n;
355
+ partialOp.paymasterVerificationGasLimit =
356
+ estimates.paymasterVerificationGasLimit || 0n;
357
+ }
358
+ return {
359
+ ...partialOp,
360
+ signature: "0x" as Hex,
361
+ };
362
+ }
363
+
364
+ async function populateUserOp_v0_6(args: {
365
+ bundlerOptions: BundlerOptions;
366
+ factoryContract: ThirdwebContract;
367
+ accountContract: ThirdwebContract;
368
+ adminAddress: string;
369
+ sponsorGas: boolean;
370
+ overrides?: SmartWalletOptions["overrides"];
371
+ isDeployed: boolean;
372
+ nonce: bigint;
373
+ callData: Hex;
374
+ maxFeePerGas: bigint;
375
+ maxPriorityFeePerGas: bigint;
376
+ }): Promise<UserOperationV06> {
377
+ const {
378
+ bundlerOptions,
379
+ isDeployed,
380
+ factoryContract,
381
+ accountContract,
382
+ adminAddress,
383
+ sponsorGas,
384
+ overrides,
385
+ nonce,
386
+ callData,
387
+ maxFeePerGas,
388
+ maxPriorityFeePerGas,
389
+ } = args;
390
+ const { chain, client } = bundlerOptions;
391
+ const initCode = isDeployed
392
+ ? "0x"
393
+ : await getAccountInitCode({
394
+ factoryContract: factoryContract,
395
+ adminAddress,
396
+ accountSalt: overrides?.accountSalt,
397
+ createAccountOverride: overrides?.createAccount,
398
+ });
399
+
400
+ const partialOp: UserOperationV06 = {
173
401
  sender: accountContract.address,
174
402
  nonce,
175
403
  initCode,
@@ -191,7 +419,10 @@ export async function createUnsignedUserOp(args: {
191
419
  entrypointAddress: overrides?.entrypointAddress,
192
420
  paymasterOverride: overrides?.paymaster,
193
421
  });
194
- const paymasterAndData = paymasterResult.paymasterAndData;
422
+ const paymasterAndData =
423
+ "paymasterAndData" in paymasterResult
424
+ ? paymasterResult.paymasterAndData
425
+ : "0x";
195
426
  if (paymasterAndData && paymasterAndData !== "0x") {
196
427
  partialOp.paymasterAndData = paymasterAndData as Hex;
197
428
  }
@@ -222,11 +453,12 @@ export async function createUnsignedUserOp(args: {
222
453
  entrypointAddress: overrides?.entrypointAddress,
223
454
  paymasterOverride: overrides?.paymaster,
224
455
  });
225
- if (
226
- paymasterResult2.paymasterAndData &&
227
- paymasterResult2.paymasterAndData !== "0x"
228
- ) {
229
- partialOp.paymasterAndData = paymasterResult2.paymasterAndData as Hex;
456
+ const paymasterAndData2 =
457
+ "paymasterAndData" in paymasterResult2
458
+ ? paymasterResult2.paymasterAndData
459
+ : "0x";
460
+ if (paymasterAndData2 && paymasterAndData2 !== "0x") {
461
+ partialOp.paymasterAndData = paymasterAndData2 as Hex;
230
462
  }
231
463
  }
232
464
  }
@@ -242,7 +474,7 @@ export async function createUnsignedUserOp(args: {
242
474
  }
243
475
  return {
244
476
  ...partialOp,
245
- signature: "0x",
477
+ signature: "0x" as Hex,
246
478
  };
247
479
  }
248
480
 
@@ -265,17 +497,41 @@ export async function createUnsignedUserOp(args: {
265
497
  * @walletUtils
266
498
  */
267
499
  export async function signUserOp(args: {
268
- userOp: UserOperation;
500
+ client: ThirdwebClient;
501
+ userOp: UserOperationV06 | UserOperationV07;
269
502
  chain: Chain;
270
503
  entrypointAddress?: string;
271
504
  adminAccount: Account;
272
- }): Promise<UserOperation> {
505
+ }): Promise<UserOperationV06 | UserOperationV07> {
273
506
  const { userOp, chain, entrypointAddress, adminAccount } = args;
274
- const userOpHash = getUserOpHash({
275
- userOp,
276
- entryPoint: entrypointAddress || ENTRYPOINT_ADDRESS_v0_6,
277
- chainId: chain.id,
278
- });
507
+
508
+ const entrypointVersion = getEntryPointVersion(
509
+ entrypointAddress || ENTRYPOINT_ADDRESS_v0_6,
510
+ );
511
+
512
+ let userOpHash: Hex;
513
+
514
+ if (entrypointVersion === "v0.7") {
515
+ const packedUserOp = getPackedUserOperation(userOp as UserOperationV07);
516
+ userOpHash = await getUserOpHashV07({
517
+ contract: getContract({
518
+ address: entrypointAddress || ENTRYPOINT_ADDRESS_v0_7,
519
+ chain,
520
+ client: args.client,
521
+ }),
522
+ userOp: packedUserOp,
523
+ });
524
+ } else {
525
+ userOpHash = await getUserOpHashV06({
526
+ contract: getContract({
527
+ address: entrypointAddress || ENTRYPOINT_ADDRESS_v0_6,
528
+ chain,
529
+ client: args.client,
530
+ }),
531
+ userOp: userOp as UserOperationV06,
532
+ });
533
+ }
534
+
279
535
  if (adminAccount.signMessage) {
280
536
  const signature = await adminAccount.signMessage({
281
537
  message: {
@@ -336,52 +592,3 @@ async function getAccountNonce(options: {
336
592
  sender: accountContract.address,
337
593
  });
338
594
  }
339
-
340
- /**
341
- * Get the hash of a user operation.
342
- * @param args - The user operation, entrypoint address, and chain ID
343
- * @returns - The hash of the user operation
344
- * @walletUtils
345
- */
346
- function getUserOpHash(args: {
347
- userOp: UserOperation;
348
- entryPoint: string;
349
- chainId: number;
350
- }): Hex {
351
- const { userOp, entryPoint, chainId } = args;
352
- const hashedInitCode = keccak256(userOp.initCode);
353
- const hashedCallData = keccak256(userOp.callData);
354
- const hashedPaymasterAndData = keccak256(userOp.paymasterAndData);
355
-
356
- const packedUserOp = encodeAbiParameters(
357
- [
358
- { type: "address" },
359
- { type: "uint256" },
360
- { type: "bytes32" },
361
- { type: "bytes32" },
362
- { type: "uint256" },
363
- { type: "uint256" },
364
- { type: "uint256" },
365
- { type: "uint256" },
366
- { type: "uint256" },
367
- { type: "bytes32" },
368
- ],
369
- [
370
- userOp.sender,
371
- userOp.nonce,
372
- hashedInitCode,
373
- hashedCallData,
374
- userOp.callGasLimit,
375
- userOp.verificationGasLimit,
376
- userOp.preVerificationGas,
377
- userOp.maxFeePerGas,
378
- userOp.maxPriorityFeePerGas,
379
- hashedPaymasterAndData,
380
- ],
381
- );
382
- const encoded = encodeAbiParameters(
383
- [{ type: "bytes32" }, { type: "address" }, { type: "uint256" }],
384
- [keccak256(packedUserOp), entryPoint, BigInt(chainId)],
385
- );
386
- return keccak256(encoded);
387
- }
@@ -1,7 +1,12 @@
1
1
  import { concat } from "viem";
2
2
  import type { Chain } from "../../../chains/types.js";
3
3
  import { isHex, numberToHex, toHex } from "../../../utils/encoding/hex.js";
4
- import type { UserOperation, UserOperationHexed } from "../types.js";
4
+ import type {
5
+ UserOperationV06,
6
+ UserOperationV06Hexed,
7
+ UserOperationV07,
8
+ UserOperationV07Hexed,
9
+ } from "../types.js";
5
10
 
6
11
  export const generateRandomUint192 = (): bigint => {
7
12
  const rand1 = BigInt(Math.floor(Math.random() * 0x100000000));
@@ -32,14 +37,16 @@ export const randomNonce = () => {
32
37
  /**
33
38
  * @internal
34
39
  */
35
- export function hexlifyUserOp(userOp: UserOperation): UserOperationHexed {
40
+ export function hexlifyUserOp(
41
+ userOp: UserOperationV06 | UserOperationV07,
42
+ ): UserOperationV06Hexed | UserOperationV07Hexed {
36
43
  return Object.fromEntries(
37
44
  Object.entries(userOp).map(([key, val]) => [
38
45
  key,
39
46
  // turn any value that's not hex into hex
40
- isHex(val) ? val : toHex(val),
47
+ val === undefined || val === null || isHex(val) ? val : toHex(val),
41
48
  ]),
42
- ) as UserOperationHexed;
49
+ ) as UserOperationV06Hexed | UserOperationV07Hexed;
43
50
  }
44
51
 
45
52
  export function isNativeAAChain(chain: Chain) {
@@ -0,0 +1,206 @@
1
+ import { beforeAll, describe, expect, it } from "vitest";
2
+ import { TEST_CLIENT } from "../../../test/src/test-clients.js";
3
+ import { typedData } from "../../../test/src/typed-data.js";
4
+ import { verifySignature } from "../../auth/verify-signature.js";
5
+ import { type ThirdwebContract, getContract } from "../../contract/contract.js";
6
+ import { parseEventLogs } from "../../event/actions/parse-logs.js";
7
+
8
+ import { sepolia } from "../../chains/chain-definitions/sepolia.js";
9
+ import {
10
+ addAdmin,
11
+ adminUpdatedEvent,
12
+ } from "../../exports/extensions/erc4337.js";
13
+ import { balanceOf } from "../../extensions/erc1155/__generated__/IERC1155/read/balanceOf.js";
14
+ import { claimTo } from "../../extensions/erc1155/drops/write/claimTo.js";
15
+ import { checkContractWalletSignature } from "../../extensions/erc1271/checkContractWalletSignature.js";
16
+ import { setContractURI } from "../../extensions/marketplace/__generated__/IMarketplace/write/setContractURI.js";
17
+ import { estimateGasCost } from "../../transaction/actions/estimate-gas-cost.js";
18
+ import { sendAndConfirmTransaction } from "../../transaction/actions/send-and-confirm-transaction.js";
19
+ import { sendBatchTransaction } from "../../transaction/actions/send-batch-transaction.js";
20
+ import { waitForReceipt } from "../../transaction/actions/wait-for-tx-receipt.js";
21
+ import { getAddress } from "../../utils/address.js";
22
+ import { isContractDeployed } from "../../utils/bytecode/is-contract-deployed.js";
23
+ import type { Account, Wallet } from "../interfaces/wallet.js";
24
+ import { generateAccount } from "../utils/generateAccount.js";
25
+ import { ENTRYPOINT_ADDRESS_v0_7 } from "./lib/constants.js";
26
+ import { smartWallet } from "./smart-wallet.js";
27
+
28
+ let wallet: Wallet;
29
+ let smartAccount: Account;
30
+ let smartWalletAddress: string;
31
+ let personalAccount: Account;
32
+ let accountContract: ThirdwebContract;
33
+
34
+ const chain = sepolia;
35
+ const client = TEST_CLIENT;
36
+ const contract = getContract({
37
+ client,
38
+ chain,
39
+ address: "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8",
40
+ });
41
+
42
+ describe.runIf(process.env.TW_SECRET_KEY).sequential(
43
+ "SmartWallet 0.7 core tests",
44
+ {
45
+ retry: 0,
46
+ timeout: 240_000,
47
+ },
48
+ () => {
49
+ beforeAll(async () => {
50
+ personalAccount = await generateAccount({
51
+ client,
52
+ });
53
+ wallet = smartWallet({
54
+ chain,
55
+ gasless: true,
56
+ overrides: {
57
+ entrypointAddress: ENTRYPOINT_ADDRESS_v0_7,
58
+ },
59
+ });
60
+ smartAccount = await wallet.connect({
61
+ client: TEST_CLIENT,
62
+ personalAccount,
63
+ });
64
+ smartWalletAddress = smartAccount.address;
65
+ accountContract = getContract({
66
+ address: smartWalletAddress,
67
+ chain,
68
+ client,
69
+ });
70
+ });
71
+
72
+ it("can connect", async () => {
73
+ expect(smartWalletAddress).toHaveLength(42);
74
+ });
75
+
76
+ it("should revert on unsuccessful transactions", async () => {
77
+ const tx = sendAndConfirmTransaction({
78
+ transaction: setContractURI({
79
+ contract,
80
+ uri: "https://example.com",
81
+ }),
82
+ account: smartAccount,
83
+ });
84
+
85
+ await expect(tx).rejects.toMatchInlineSnapshot(`
86
+ [TransactionError: Error - Not authorized
87
+
88
+ contract: ${contract.address}
89
+ chainId: 11155111]
90
+ `);
91
+ });
92
+
93
+ it("can execute a tx", async () => {
94
+ const tx = await sendAndConfirmTransaction({
95
+ transaction: claimTo({
96
+ contract,
97
+ quantity: 1n,
98
+ to: smartWalletAddress,
99
+ tokenId: 0n,
100
+ }),
101
+ account: smartAccount,
102
+ });
103
+ expect(tx.transactionHash).toHaveLength(66);
104
+ const isDeployed = await isContractDeployed(accountContract);
105
+ expect(isDeployed).toEqual(true);
106
+ const balance = await balanceOf({
107
+ contract,
108
+ owner: getAddress(smartWalletAddress),
109
+ tokenId: 0n,
110
+ });
111
+ expect(balance).toEqual(1n);
112
+ });
113
+
114
+ it("can estimate a tx", async () => {
115
+ const estimates = await estimateGasCost({
116
+ transaction: claimTo({
117
+ contract,
118
+ quantity: 1n,
119
+ to: smartWalletAddress,
120
+ tokenId: 0n,
121
+ }),
122
+ account: smartAccount,
123
+ });
124
+ expect(estimates.wei.toString()).not.toBe("0");
125
+ });
126
+
127
+ it("can execute a batched tx", async () => {
128
+ const tx = await sendBatchTransaction({
129
+ account: smartAccount,
130
+ transactions: [
131
+ claimTo({
132
+ contract,
133
+ quantity: 1n,
134
+ to: smartWalletAddress,
135
+ tokenId: 0n,
136
+ }),
137
+ claimTo({
138
+ contract,
139
+ quantity: 1n,
140
+ to: smartWalletAddress,
141
+ tokenId: 0n,
142
+ }),
143
+ ],
144
+ });
145
+ expect(tx.transactionHash).toHaveLength(66);
146
+ await waitForReceipt({
147
+ client,
148
+ transactionHash: tx.transactionHash,
149
+ chain,
150
+ });
151
+ const balance = await balanceOf({
152
+ contract,
153
+ owner: getAddress(smartWalletAddress),
154
+ tokenId: 0n,
155
+ });
156
+ expect(balance).toEqual(3n);
157
+ });
158
+
159
+ it("can sign and verify 1271 with replay protection", async () => {
160
+ const message = "hello world";
161
+ const signature = await smartAccount.signMessage({ message });
162
+ const isValidV1 = await verifySignature({
163
+ message,
164
+ signature,
165
+ address: smartWalletAddress,
166
+ chain,
167
+ client,
168
+ });
169
+ expect(isValidV1).toEqual(true);
170
+ const isValidV2 = await checkContractWalletSignature({
171
+ message,
172
+ signature,
173
+ contract: accountContract,
174
+ });
175
+ expect(isValidV2).toEqual(true);
176
+
177
+ // sign typed data
178
+ const signatureTyped = await smartAccount.signTypedData({
179
+ ...typedData.basic,
180
+ primaryType: "Mail",
181
+ });
182
+ expect(signatureTyped.length).toBe(132);
183
+
184
+ // add admin
185
+ const newAdmin = await generateAccount({ client });
186
+ const receipt = await sendAndConfirmTransaction({
187
+ account: smartAccount,
188
+ transaction: addAdmin({
189
+ account: smartAccount,
190
+ adminAddress: newAdmin.address,
191
+ contract: getContract({
192
+ address: smartAccount.address,
193
+ chain,
194
+ client,
195
+ }),
196
+ }),
197
+ });
198
+ const logs = parseEventLogs({
199
+ events: [adminUpdatedEvent()],
200
+ logs: receipt.logs,
201
+ });
202
+ expect(logs.some((l) => l.args.signer === newAdmin.address)).toBe(true);
203
+ expect(logs.some((l) => l.args.isAdmin)).toBe(true);
204
+ });
205
+ },
206
+ );