thirdweb 5.89.1 → 5.90.0

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 (114) hide show
  1. package/dist/cjs/chains/constants.js +17 -2
  2. package/dist/cjs/chains/constants.js.map +1 -1
  3. package/dist/cjs/exports/wallets/smart.js +2 -1
  4. package/dist/cjs/exports/wallets/smart.js.map +1 -1
  5. package/dist/cjs/storage/download.js +16 -0
  6. package/dist/cjs/storage/download.js.map +1 -1
  7. package/dist/cjs/storage/mock.js +46 -0
  8. package/dist/cjs/storage/mock.js.map +1 -0
  9. package/dist/cjs/storage/upload/web-node.js +6 -1
  10. package/dist/cjs/storage/upload/web-node.js.map +1 -1
  11. package/dist/cjs/transaction/actions/estimate-gas-cost.js +1 -1
  12. package/dist/cjs/transaction/actions/estimate-gas-cost.js.map +1 -1
  13. package/dist/cjs/utils/process.js +4 -1
  14. package/dist/cjs/utils/process.js.map +1 -1
  15. package/dist/cjs/version.js +1 -1
  16. package/dist/cjs/wallets/manager/index.js +1 -1
  17. package/dist/cjs/wallets/manager/index.js.map +1 -1
  18. package/dist/cjs/wallets/smart/index.js +1 -0
  19. package/dist/cjs/wallets/smart/index.js.map +1 -1
  20. package/dist/cjs/wallets/smart/lib/bundler.js +75 -0
  21. package/dist/cjs/wallets/smart/lib/bundler.js.map +1 -1
  22. package/dist/cjs/wallets/smart/lib/userop.js +35 -13
  23. package/dist/cjs/wallets/smart/lib/userop.js.map +1 -1
  24. package/dist/esm/chains/constants.js +17 -2
  25. package/dist/esm/chains/constants.js.map +1 -1
  26. package/dist/esm/exports/wallets/smart.js +1 -1
  27. package/dist/esm/exports/wallets/smart.js.map +1 -1
  28. package/dist/esm/storage/download.js +16 -0
  29. package/dist/esm/storage/download.js.map +1 -1
  30. package/dist/esm/storage/mock.js +42 -0
  31. package/dist/esm/storage/mock.js.map +1 -0
  32. package/dist/esm/storage/upload/web-node.js +6 -1
  33. package/dist/esm/storage/upload/web-node.js.map +1 -1
  34. package/dist/esm/transaction/actions/estimate-gas-cost.js +1 -1
  35. package/dist/esm/transaction/actions/estimate-gas-cost.js.map +1 -1
  36. package/dist/esm/utils/process.js +3 -0
  37. package/dist/esm/utils/process.js.map +1 -1
  38. package/dist/esm/version.js +1 -1
  39. package/dist/esm/wallets/manager/index.js +1 -1
  40. package/dist/esm/wallets/manager/index.js.map +1 -1
  41. package/dist/esm/wallets/smart/index.js +1 -1
  42. package/dist/esm/wallets/smart/index.js.map +1 -1
  43. package/dist/esm/wallets/smart/lib/bundler.js +74 -0
  44. package/dist/esm/wallets/smart/lib/bundler.js.map +1 -1
  45. package/dist/esm/wallets/smart/lib/userop.js +34 -13
  46. package/dist/esm/wallets/smart/lib/userop.js.map +1 -1
  47. package/dist/types/chains/constants.d.ts +1 -1
  48. package/dist/types/chains/constants.d.ts.map +1 -1
  49. package/dist/types/exports/wallets/smart.d.ts +1 -1
  50. package/dist/types/exports/wallets/smart.d.ts.map +1 -1
  51. package/dist/types/storage/download.d.ts.map +1 -1
  52. package/dist/types/storage/mock.d.ts +11 -0
  53. package/dist/types/storage/mock.d.ts.map +1 -0
  54. package/dist/types/storage/upload/web-node.d.ts.map +1 -1
  55. package/dist/types/utils/process.d.ts +1 -0
  56. package/dist/types/utils/process.d.ts.map +1 -1
  57. package/dist/types/version.d.ts +1 -1
  58. package/dist/types/wallets/manager/index.d.ts +1 -1
  59. package/dist/types/wallets/manager/index.d.ts.map +1 -1
  60. package/dist/types/wallets/smart/index.d.ts +2 -0
  61. package/dist/types/wallets/smart/index.d.ts.map +1 -1
  62. package/dist/types/wallets/smart/lib/bundler.d.ts +30 -1
  63. package/dist/types/wallets/smart/lib/bundler.d.ts.map +1 -1
  64. package/dist/types/wallets/smart/lib/userop.d.ts +8 -0
  65. package/dist/types/wallets/smart/lib/userop.d.ts.map +1 -1
  66. package/package.json +7 -7
  67. package/src/adapters/viem-legacy.test.ts +1 -1
  68. package/src/auth/verify-typed-data.test.ts +2 -4
  69. package/src/chains/constants.ts +17 -2
  70. package/src/contract/actions/resolve-abi.test.ts +3 -3
  71. package/src/exports/wallets/smart.ts +1 -0
  72. package/src/extensions/erc1155/customDrop1155.test.ts +3 -14
  73. package/src/extensions/erc1155/drop1155.test.ts +3 -14
  74. package/src/extensions/erc1155/token1155.test.ts +16 -109
  75. package/src/extensions/erc20/read/getCurrencyMetadata.test.ts +1 -1
  76. package/src/extensions/erc721/customDrop721.test.ts +3 -13
  77. package/src/extensions/erc721/drop721.test.ts +3 -13
  78. package/src/extensions/erc721/read/getNFTs.test.ts +1 -1
  79. package/src/extensions/erc721/read/getOwnedTokenIds.test.ts +1 -1
  80. package/src/extensions/lens/read/resolveAddress.test.ts +1 -1
  81. package/src/extensions/prebuilts/deploy-vote.test.ts +1 -1
  82. package/src/extensions/unstoppable-domains/read/resolveAddress.test.ts +1 -1
  83. package/src/extensions/unstoppable-domains/read/resolveName.test.ts +1 -1
  84. package/src/pay/convert/cryptoToFiat.test.ts +4 -4
  85. package/src/pay/convert/fiatToCrypto.test.ts +4 -4
  86. package/src/react/core/hooks/wallets/useConnect.test.tsx +3 -3
  87. package/src/react/web/ui/prebuilt/Account/balance.test.tsx +7 -13
  88. package/src/react/web/ui/prebuilt/Chain/icon.test.tsx +1 -1
  89. package/src/react/web/ui/prebuilt/NFT/description.test.tsx +1 -1
  90. package/src/react/web/ui/prebuilt/NFT/media.test.tsx +1 -1
  91. package/src/react/web/ui/prebuilt/NFT/name.test.tsx +1 -1
  92. package/src/react/web/ui/prebuilt/NFT/utils.test.ts +1 -1
  93. package/src/react/web/ui/prebuilt/Token/name.test.tsx +1 -1
  94. package/src/react/web/ui/prebuilt/Token/symbol.test.tsx +1 -1
  95. package/src/react/web/ui/prebuilt/Wallet/icon.test.tsx +1 -1
  96. package/src/react/web/ui/prebuilt/Wallet/name.test.tsx +1 -1
  97. package/src/react/web/ui/prebuilt/thirdweb/ClaimButton/ClaimButton.test.tsx +1 -1
  98. package/src/storage/download.test.ts +1 -1
  99. package/src/storage/download.ts +17 -0
  100. package/src/storage/mock.ts +52 -0
  101. package/src/storage/upload/web-node.test.ts +2 -1
  102. package/src/storage/upload/web-node.ts +8 -1
  103. package/src/transaction/actions/encode.test.ts +1 -1
  104. package/src/transaction/actions/estimate-gas-cost.ts +1 -1
  105. package/src/utils/nft/fetch-token-metadata.test.ts +1 -1
  106. package/src/utils/process.ts +4 -0
  107. package/src/version.ts +1 -1
  108. package/src/wallets/manager/index.ts +6 -2
  109. package/src/wallets/smart/index.ts +1 -1
  110. package/src/wallets/smart/lib/bundler.ts +95 -0
  111. package/src/wallets/smart/lib/userop.ts +42 -15
  112. package/src/wallets/smart/smart-wallet-integration-v07.test.ts +25 -21
  113. package/src/wallets/smart/smart-wallet-integration.test.ts +21 -1
  114. package/src/wallets/smart/smart-wallet-modular.test.ts +1 -2
@@ -1,27 +1,37 @@
1
1
  import { decodeErrorResult } from "viem";
2
+ import type { ThirdwebClient } from "../../../client/client.js";
3
+ import { getContract } from "../../../contract/contract.js";
2
4
  import { parseEventLogs } from "../../../event/actions/parse-logs.js";
3
5
  import { userOperationRevertReasonEvent } from "../../../extensions/erc4337/__generated__/IEntryPoint/events/UserOperationRevertReason.js";
4
6
  import { postOpRevertReasonEvent } from "../../../extensions/erc4337/__generated__/IEntryPoint_v07/events/PostOpRevertReason.js";
7
+ import type { PreparedTransaction } from "../../../transaction/prepare-transaction.js";
5
8
  import type { SerializableTransaction } from "../../../transaction/serialize-transaction.js";
6
9
  import type { TransactionReceipt } from "../../../transaction/types.js";
10
+ import { isContractDeployed } from "../../../utils/bytecode/is-contract-deployed.js";
7
11
  import { type Hex, hexToBigInt } from "../../../utils/encoding/hex.js";
8
12
  import { getClientFetch } from "../../../utils/fetch.js";
9
13
  import { stringify } from "../../../utils/json.js";
14
+ import { toEther } from "../../../utils/units.js";
15
+ import type { Account } from "../../interfaces/wallet.js";
16
+ import { getEntrypointFromFactory } from "../index.js";
10
17
  import {
11
18
  type BundlerOptions,
12
19
  type EstimationResult,
13
20
  type GasPriceResult,
14
21
  type PmTransactionData,
22
+ type SmartWalletOptions,
15
23
  type UserOperationReceipt,
16
24
  type UserOperationV06,
17
25
  type UserOperationV07,
18
26
  formatUserOperationReceipt,
19
27
  } from "../types.js";
28
+ import { predictSmartAccountAddress } from "./calls.js";
20
29
  import {
21
30
  ENTRYPOINT_ADDRESS_v0_6,
22
31
  MANAGED_ACCOUNT_GAS_BUFFER,
23
32
  getDefaultBundlerUrl,
24
33
  } from "./constants.js";
34
+ import { prepareUserOp } from "./userop.js";
25
35
  import { hexlifyUserOp } from "./utils.js";
26
36
 
27
37
  /**
@@ -111,6 +121,91 @@ export async function estimateUserOpGas(
111
121
  };
112
122
  }
113
123
 
124
+ /**
125
+ * Estimate the gas cost of a user operation.
126
+ * @param args - The options for estimating the gas cost of a user operation.
127
+ * @returns The estimated gas cost of the user operation.
128
+ * @example
129
+ * ```ts
130
+ * import { estimateUserOpGasCost } from "thirdweb/wallets/smart";
131
+ *
132
+ * const gasCost = await estimateUserOpGasCost({
133
+ * transactions,
134
+ * adminAccount,
135
+ * client,
136
+ * smartWalletOptions,
137
+ * });
138
+ * ```
139
+ * @walletUtils
140
+ */
141
+ export async function estimateUserOpGasCost(args: {
142
+ transactions: PreparedTransaction[];
143
+ adminAccount: Account;
144
+ client: ThirdwebClient;
145
+ smartWalletOptions: SmartWalletOptions;
146
+ }) {
147
+ // if factory is passed, but no entrypoint, try to resolve entrypoint from factory
148
+ if (
149
+ args.smartWalletOptions.factoryAddress &&
150
+ !args.smartWalletOptions.overrides?.entrypointAddress
151
+ ) {
152
+ const entrypointAddress = await getEntrypointFromFactory(
153
+ args.smartWalletOptions.factoryAddress,
154
+ args.client,
155
+ args.smartWalletOptions.chain,
156
+ );
157
+ if (entrypointAddress) {
158
+ args.smartWalletOptions.overrides = {
159
+ ...args.smartWalletOptions.overrides,
160
+ entrypointAddress,
161
+ };
162
+ }
163
+ }
164
+
165
+ const userOp = await prepareUserOp({
166
+ transactions: args.transactions,
167
+ adminAccount: args.adminAccount,
168
+ client: args.client,
169
+ smartWalletOptions: args.smartWalletOptions,
170
+ isDeployedOverride: await isContractDeployed(
171
+ getContract({
172
+ address: await predictSmartAccountAddress({
173
+ adminAddress: args.adminAccount.address,
174
+ factoryAddress: args.smartWalletOptions.factoryAddress,
175
+ chain: args.smartWalletOptions.chain,
176
+ client: args.client,
177
+ }),
178
+ chain: args.smartWalletOptions.chain,
179
+ client: args.client,
180
+ }),
181
+ ),
182
+ });
183
+
184
+ let gasLimit = 0n;
185
+ if ("paymasterVerificationGasLimit" in userOp) {
186
+ // v0.7
187
+ gasLimit =
188
+ BigInt(userOp.paymasterVerificationGasLimit ?? 0) +
189
+ BigInt(userOp.paymasterPostOpGasLimit ?? 0) +
190
+ BigInt(userOp.verificationGasLimit ?? 0) +
191
+ BigInt(userOp.preVerificationGas ?? 0) +
192
+ BigInt(userOp.callGasLimit ?? 0);
193
+ } else {
194
+ // v0.6
195
+ gasLimit =
196
+ BigInt(userOp.verificationGasLimit ?? 0) +
197
+ BigInt(userOp.preVerificationGas ?? 0) +
198
+ BigInt(userOp.callGasLimit ?? 0);
199
+ }
200
+
201
+ const gasCost = gasLimit * (userOp.maxFeePerGas ?? 0n);
202
+
203
+ return {
204
+ ether: toEther(gasCost),
205
+ wei: gasCost,
206
+ };
207
+ }
208
+
114
209
  /**
115
210
  * Get the gas fees of a user operation.
116
211
  * @param args - The options for getting the gas price of a user operation.
@@ -706,6 +706,32 @@ export async function createAndSignUserOp(options: {
706
706
  smartWalletOptions: SmartWalletOptions;
707
707
  waitForDeployment?: boolean;
708
708
  isDeployedOverride?: boolean;
709
+ }) {
710
+ const unsignedUserOp = await prepareUserOp({
711
+ transactions: options.transactions,
712
+ adminAccount: options.adminAccount,
713
+ client: options.client,
714
+ smartWalletOptions: options.smartWalletOptions,
715
+ waitForDeployment: options.waitForDeployment,
716
+ isDeployedOverride: options.isDeployedOverride,
717
+ });
718
+ const signedUserOp = await signUserOp({
719
+ client: options.client,
720
+ chain: options.smartWalletOptions.chain,
721
+ adminAccount: options.adminAccount,
722
+ entrypointAddress: options.smartWalletOptions.overrides?.entrypointAddress,
723
+ userOp: unsignedUserOp,
724
+ });
725
+ return signedUserOp;
726
+ }
727
+
728
+ export async function prepareUserOp(options: {
729
+ transactions: PreparedTransaction[];
730
+ adminAccount: Account;
731
+ client: ThirdwebClient;
732
+ smartWalletOptions: SmartWalletOptions;
733
+ waitForDeployment?: boolean;
734
+ isDeployedOverride?: boolean;
709
735
  }) {
710
736
  const config = options.smartWalletOptions;
711
737
  const factoryContract = getContract({
@@ -731,6 +757,7 @@ export async function createAndSignUserOp(options: {
731
757
  let executeTx: PreparedTransaction;
732
758
  if (options.transactions.length === 1) {
733
759
  const tx = options.transactions[0] as PreparedTransaction;
760
+ // for single tx, simulate fully
734
761
  const serializedTx = await toSerializableTransaction({
735
762
  transaction: tx,
736
763
  from: accountAddress,
@@ -741,13 +768,21 @@ export async function createAndSignUserOp(options: {
741
768
  executeOverride: config.overrides?.execute,
742
769
  });
743
770
  } else {
771
+ // for multiple txs, we can't simulate, just encode
744
772
  const serializedTxs = await Promise.all(
745
- options.transactions.map((tx) =>
746
- toSerializableTransaction({
747
- transaction: tx,
748
- from: accountAddress,
749
- }),
750
- ),
773
+ options.transactions.map(async (tx) => {
774
+ const [data, to, value] = await Promise.all([
775
+ encode(tx),
776
+ resolvePromisedValue(tx.to),
777
+ resolvePromisedValue(tx.value),
778
+ ]);
779
+ return {
780
+ data,
781
+ to,
782
+ value,
783
+ chainId: tx.chain.id,
784
+ };
785
+ }),
751
786
  );
752
787
  executeTx = prepareBatchExecute({
753
788
  accountContract,
@@ -756,7 +791,7 @@ export async function createAndSignUserOp(options: {
756
791
  });
757
792
  }
758
793
 
759
- const unsignedUserOp = await createUnsignedUserOp({
794
+ return createUnsignedUserOp({
760
795
  transaction: executeTx,
761
796
  factoryContract,
762
797
  accountContract,
@@ -766,14 +801,6 @@ export async function createAndSignUserOp(options: {
766
801
  waitForDeployment: options.waitForDeployment,
767
802
  isDeployedOverride: options.isDeployedOverride,
768
803
  });
769
- const signedUserOp = await signUserOp({
770
- client: options.client,
771
- chain: config.chain,
772
- adminAccount: options.adminAccount,
773
- entrypointAddress: config.overrides?.entrypointAddress,
774
- userOp: unsignedUserOp,
775
- });
776
- return signedUserOp;
777
804
  }
778
805
 
779
806
  async function waitForAccountDeployed(accountContract: ThirdwebContract) {
@@ -16,7 +16,6 @@ import {
16
16
  } from "../../exports/extensions/erc4337.js";
17
17
  import { claimTo } from "../../extensions/erc1155/drops/write/claimTo.js";
18
18
  import { setContractURI } from "../../extensions/marketplace/__generated__/IMarketplace/write/setContractURI.js";
19
- import { estimateGasCost } from "../../transaction/actions/estimate-gas-cost.js";
20
19
  import { sendAndConfirmTransaction } from "../../transaction/actions/send-and-confirm-transaction.js";
21
20
  import { sendBatchTransaction } from "../../transaction/actions/send-batch-transaction.js";
22
21
  import { waitForReceipt } from "../../transaction/actions/wait-for-tx-receipt.js";
@@ -27,6 +26,7 @@ import { hashTypedData } from "../../utils/hashing/hashTypedData.js";
27
26
  import { sleep } from "../../utils/sleep.js";
28
27
  import type { Account, Wallet } from "../interfaces/wallet.js";
29
28
  import { generateAccount } from "../utils/generateAccount.js";
29
+ import { estimateUserOpGasCost } from "./lib/bundler.js";
30
30
  import { predictSmartAccountAddress } from "./lib/calls.js";
31
31
  import { DEFAULT_ACCOUNT_FACTORY_V0_7 } from "./lib/constants.js";
32
32
  import {
@@ -49,11 +49,9 @@ const contract = getContract({
49
49
  address: "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8",
50
50
  });
51
51
 
52
- // FIXME: SKIP ALL OF THIS IT IS FLAKY
53
- describe.skip(
52
+ describe.sequential(
54
53
  "SmartWallet 0.7 core tests",
55
54
  {
56
- retry: 0,
57
55
  timeout: 240_000,
58
56
  },
59
57
  () => {
@@ -89,6 +87,27 @@ describe.skip(
89
87
  expect(predictedAddress).toEqual(smartWalletAddress);
90
88
  });
91
89
 
90
+ it("can estimate gas cost", async () => {
91
+ const gasCost = await estimateUserOpGasCost({
92
+ transactions: [
93
+ claimTo({
94
+ contract,
95
+ quantity: 1n,
96
+ to: smartWalletAddress,
97
+ tokenId: 0n,
98
+ }),
99
+ ],
100
+ adminAccount: personalAccount,
101
+ client: TEST_CLIENT,
102
+ smartWalletOptions: {
103
+ chain,
104
+ sponsorGas: true,
105
+ factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_7,
106
+ },
107
+ });
108
+ expect(gasCost.ether).not.toBe("0");
109
+ });
110
+
92
111
  it("can sign a msg", async () => {
93
112
  const signature = await smartAccount.signMessage({
94
113
  message: "hello world",
@@ -103,8 +122,7 @@ describe.skip(
103
122
  expect(isValid).toEqual(true);
104
123
  });
105
124
 
106
- // FIXME: flaky test - skipped
107
- it.skip("should use ERC-1271 signatures after deployment", async () => {
125
+ it("should use ERC-1271 signatures after deployment", async () => {
108
126
  await deploySmartAccount({
109
127
  chain,
110
128
  client,
@@ -137,8 +155,7 @@ describe.skip(
137
155
  expect(isValid).toEqual(true);
138
156
  });
139
157
 
140
- // FIXME: flaky test - skipped
141
- it.skip("should use ERC-1271 typed data signatures after deployment", async () => {
158
+ it("should use ERC-1271 typed data signatures after deployment", async () => {
142
159
  await deploySmartAccount({
143
160
  chain,
144
161
  client,
@@ -206,19 +223,6 @@ describe.skip(
206
223
  expect(isDeployed).toEqual(true);
207
224
  });
208
225
 
209
- it("can estimate a tx", async () => {
210
- const estimates = await estimateGasCost({
211
- transaction: claimTo({
212
- contract,
213
- quantity: 1n,
214
- to: smartWalletAddress,
215
- tokenId: 0n,
216
- }),
217
- account: smartAccount,
218
- });
219
- expect(estimates.wei.toString()).not.toBe("0");
220
- });
221
-
222
226
  it("can execute a batched tx", async () => {
223
227
  const tx = await sendBatchTransaction({
224
228
  account: smartAccount,
@@ -29,6 +29,7 @@ import { hashTypedData } from "../../utils/hashing/hashTypedData.js";
29
29
  import { sleep } from "../../utils/sleep.js";
30
30
  import type { Account, Wallet } from "../interfaces/wallet.js";
31
31
  import { generateAccount } from "../utils/generateAccount.js";
32
+ import { estimateUserOpGasCost } from "./lib/bundler.js";
32
33
  import { predictSmartAccountAddress } from "./lib/calls.js";
33
34
  import { deploySmartAccount } from "./lib/signing.js";
34
35
  import { smartWallet } from "./smart-wallet.js";
@@ -51,7 +52,6 @@ const factoryAddress = "0x564cf6453a1b0FF8DB603E92EA4BbD410dea45F3"; // pre 712
51
52
  describe.runIf(process.env.TW_SECRET_KEY).sequential(
52
53
  "SmartWallet core tests",
53
54
  {
54
- retry: 0,
55
55
  timeout: 240_000,
56
56
  },
57
57
  () => {
@@ -75,6 +75,26 @@ describe.runIf(process.env.TW_SECRET_KEY).sequential(
75
75
  });
76
76
  });
77
77
 
78
+ it("can estimate gas cost", async () => {
79
+ const gasCost = await estimateUserOpGasCost({
80
+ transactions: [
81
+ claimTo({
82
+ contract,
83
+ quantity: 1n,
84
+ to: smartWalletAddress,
85
+ tokenId: 0n,
86
+ }),
87
+ ],
88
+ adminAccount: personalAccount,
89
+ client: TEST_CLIENT,
90
+ smartWalletOptions: {
91
+ chain,
92
+ sponsorGas: true,
93
+ },
94
+ });
95
+ expect(gasCost.ether).not.toBe("0");
96
+ });
97
+
78
98
  it("can connect", async () => {
79
99
  expect(smartWalletAddress).toHaveLength(42);
80
100
  const predictedAddress = await predictSmartAccountAddress({
@@ -28,8 +28,7 @@ const client = TEST_CLIENT;
28
28
  const DEFAULT_FACTORY_ADDRESS = "0xB1846E893CA01c5Dcdaa40371C1e13f2e0Df5717";
29
29
  const DEFAULT_VALIDATOR_ADDRESS = "0x7D3631d823e0De311DC86f580946EeF2eEC81fba";
30
30
 
31
- // FIXME: This test is flaky and needs to be fixed
32
- describe.skip.sequential(
31
+ describe.sequential(
33
32
  "SmartWallet modular tests",
34
33
  {
35
34
  retry: 0,