thirdweb 5.105.21 → 5.105.23

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 (145) hide show
  1. package/dist/cjs/extensions/erc1155/read/getOwnedNFTs.js +1 -0
  2. package/dist/cjs/extensions/erc1155/read/getOwnedNFTs.js.map +1 -1
  3. package/dist/cjs/extensions/erc721/read/getOwnedNFTs.js +1 -0
  4. package/dist/cjs/extensions/erc721/read/getOwnedNFTs.js.map +1 -1
  5. package/dist/cjs/insight/get-nfts.js +3 -3
  6. package/dist/cjs/insight/get-nfts.js.map +1 -1
  7. package/dist/cjs/insight/get-tokens.js +3 -2
  8. package/dist/cjs/insight/get-tokens.js.map +1 -1
  9. package/dist/cjs/react/web/wallets/shared/WalletConnectConnection.js +7 -33
  10. package/dist/cjs/react/web/wallets/shared/WalletConnectConnection.js.map +1 -1
  11. package/dist/cjs/transaction/actions/estimate-gas.js +3 -24
  12. package/dist/cjs/transaction/actions/estimate-gas.js.map +1 -1
  13. package/dist/cjs/utils/web/isMobile.js +0 -2
  14. package/dist/cjs/utils/web/isMobile.js.map +1 -1
  15. package/dist/cjs/version.js +1 -1
  16. package/dist/cjs/wallets/coinbase/coinbase-web.js +56 -0
  17. package/dist/cjs/wallets/coinbase/coinbase-web.js.map +1 -1
  18. package/dist/cjs/wallets/create-wallet.js +21 -4
  19. package/dist/cjs/wallets/create-wallet.js.map +1 -1
  20. package/dist/cjs/wallets/eip5792/get-calls-status.js +40 -63
  21. package/dist/cjs/wallets/eip5792/get-calls-status.js.map +1 -1
  22. package/dist/cjs/wallets/eip5792/get-capabilities.js +14 -49
  23. package/dist/cjs/wallets/eip5792/get-capabilities.js.map +1 -1
  24. package/dist/cjs/wallets/eip5792/send-calls.js +34 -48
  25. package/dist/cjs/wallets/eip5792/send-calls.js.map +1 -1
  26. package/dist/cjs/wallets/in-app/core/{eip5972 → eip5792}/in-app-wallet-calls.js +1 -5
  27. package/dist/cjs/wallets/in-app/core/eip5792/in-app-wallet-calls.js.map +1 -0
  28. package/dist/cjs/wallets/in-app/core/eip7702/minimal-account.js +650 -5
  29. package/dist/cjs/wallets/in-app/core/eip7702/minimal-account.js.map +1 -1
  30. package/dist/cjs/wallets/in-app/core/wallet/enclave-wallet.js +32 -1
  31. package/dist/cjs/wallets/in-app/core/wallet/enclave-wallet.js.map +1 -1
  32. package/dist/cjs/wallets/injected/index.js +55 -0
  33. package/dist/cjs/wallets/injected/index.js.map +1 -1
  34. package/dist/cjs/wallets/smart/index.js +61 -0
  35. package/dist/cjs/wallets/smart/index.js.map +1 -1
  36. package/dist/cjs/wallets/wallet-connect/controller.js +27 -25
  37. package/dist/cjs/wallets/wallet-connect/controller.js.map +1 -1
  38. package/dist/esm/extensions/erc1155/read/getOwnedNFTs.js +1 -0
  39. package/dist/esm/extensions/erc1155/read/getOwnedNFTs.js.map +1 -1
  40. package/dist/esm/extensions/erc721/read/getOwnedNFTs.js +1 -0
  41. package/dist/esm/extensions/erc721/read/getOwnedNFTs.js.map +1 -1
  42. package/dist/esm/insight/get-nfts.js +3 -3
  43. package/dist/esm/insight/get-nfts.js.map +1 -1
  44. package/dist/esm/insight/get-tokens.js +3 -2
  45. package/dist/esm/insight/get-tokens.js.map +1 -1
  46. package/dist/esm/react/web/wallets/shared/WalletConnectConnection.js +8 -34
  47. package/dist/esm/react/web/wallets/shared/WalletConnectConnection.js.map +1 -1
  48. package/dist/esm/transaction/actions/estimate-gas.js +3 -24
  49. package/dist/esm/transaction/actions/estimate-gas.js.map +1 -1
  50. package/dist/esm/utils/web/isMobile.js +2 -2
  51. package/dist/esm/utils/web/isMobile.js.map +1 -1
  52. package/dist/esm/version.js +1 -1
  53. package/dist/esm/wallets/coinbase/coinbase-web.js +56 -0
  54. package/dist/esm/wallets/coinbase/coinbase-web.js.map +1 -1
  55. package/dist/esm/wallets/create-wallet.js +21 -4
  56. package/dist/esm/wallets/create-wallet.js.map +1 -1
  57. package/dist/esm/wallets/eip5792/get-calls-status.js +39 -63
  58. package/dist/esm/wallets/eip5792/get-calls-status.js.map +1 -1
  59. package/dist/esm/wallets/eip5792/get-capabilities.js +13 -49
  60. package/dist/esm/wallets/eip5792/get-capabilities.js.map +1 -1
  61. package/dist/esm/wallets/eip5792/send-calls.js +33 -48
  62. package/dist/esm/wallets/eip5792/send-calls.js.map +1 -1
  63. package/dist/esm/wallets/in-app/core/{eip5972 → eip5792}/in-app-wallet-calls.js +1 -5
  64. package/dist/esm/wallets/in-app/core/eip5792/in-app-wallet-calls.js.map +1 -0
  65. package/dist/esm/wallets/in-app/core/eip7702/minimal-account.js +650 -5
  66. package/dist/esm/wallets/in-app/core/eip7702/minimal-account.js.map +1 -1
  67. package/dist/esm/wallets/in-app/core/wallet/enclave-wallet.js +32 -1
  68. package/dist/esm/wallets/in-app/core/wallet/enclave-wallet.js.map +1 -1
  69. package/dist/esm/wallets/injected/index.js +56 -1
  70. package/dist/esm/wallets/injected/index.js.map +1 -1
  71. package/dist/esm/wallets/smart/index.js +61 -0
  72. package/dist/esm/wallets/smart/index.js.map +1 -1
  73. package/dist/esm/wallets/wallet-connect/controller.js +27 -25
  74. package/dist/esm/wallets/wallet-connect/controller.js.map +1 -1
  75. package/dist/types/bridge/Webhook.d.ts +2 -2
  76. package/dist/types/insight/get-nfts.d.ts +1 -0
  77. package/dist/types/insight/get-nfts.d.ts.map +1 -1
  78. package/dist/types/insight/get-tokens.d.ts +1 -0
  79. package/dist/types/insight/get-tokens.d.ts.map +1 -1
  80. package/dist/types/react/core/hooks/wallets/useWaitForCallsReceipt.d.ts +1 -1
  81. package/dist/types/react/core/utils/storage.d.ts +1 -1
  82. package/dist/types/react/web/utils/storage.d.ts +1 -1
  83. package/dist/types/react/web/wallets/shared/WalletConnectConnection.d.ts.map +1 -1
  84. package/dist/types/transaction/actions/estimate-gas.d.ts.map +1 -1
  85. package/dist/types/utils/web/isMobile.d.ts +0 -8
  86. package/dist/types/utils/web/isMobile.d.ts.map +1 -1
  87. package/dist/types/version.d.ts +1 -1
  88. package/dist/types/wallets/coinbase/coinbase-web.d.ts.map +1 -1
  89. package/dist/types/wallets/create-wallet.d.ts.map +1 -1
  90. package/dist/types/wallets/eip5792/get-calls-status.d.ts +2 -1
  91. package/dist/types/wallets/eip5792/get-calls-status.d.ts.map +1 -1
  92. package/dist/types/wallets/eip5792/get-capabilities.d.ts +1 -0
  93. package/dist/types/wallets/eip5792/get-capabilities.d.ts.map +1 -1
  94. package/dist/types/wallets/eip5792/send-calls.d.ts +6 -1
  95. package/dist/types/wallets/eip5792/send-calls.d.ts.map +1 -1
  96. package/dist/types/wallets/in-app/core/{eip5972 → eip5792}/in-app-wallet-calls.d.ts +3 -2
  97. package/dist/types/wallets/in-app/core/eip5792/in-app-wallet-calls.d.ts.map +1 -0
  98. package/dist/types/wallets/in-app/core/eip7702/minimal-account.d.ts.map +1 -1
  99. package/dist/types/wallets/in-app/core/wallet/enclave-wallet.d.ts.map +1 -1
  100. package/dist/types/wallets/injected/index.d.ts.map +1 -1
  101. package/dist/types/wallets/interfaces/wallet.d.ts +22 -0
  102. package/dist/types/wallets/interfaces/wallet.d.ts.map +1 -1
  103. package/dist/types/wallets/smart/index.d.ts.map +1 -1
  104. package/dist/types/wallets/wallet-connect/controller.d.ts.map +1 -1
  105. package/package.json +3 -3
  106. package/src/extensions/erc1155/read/getOwnedNFTs.ts +1 -0
  107. package/src/extensions/erc721/read/getOwnedNFTs.ts +1 -0
  108. package/src/insight/get-nfts.ts +4 -3
  109. package/src/insight/get-tokens.ts +4 -2
  110. package/src/react/web/wallets/shared/WalletConnectConnection.tsx +11 -46
  111. package/src/transaction/actions/estimate-gas.ts +14 -42
  112. package/src/utils/web/isMobile.ts +2 -2
  113. package/src/version.ts +1 -1
  114. package/src/wallets/coinbase/coinbase-web.ts +66 -0
  115. package/src/wallets/create-wallet.ts +53 -31
  116. package/src/wallets/eip5792/get-calls-status.test.ts +156 -146
  117. package/src/wallets/eip5792/get-calls-status.ts +44 -73
  118. package/src/wallets/eip5792/get-capabilities.test.ts +216 -205
  119. package/src/wallets/eip5792/get-capabilities.ts +23 -64
  120. package/src/wallets/eip5792/send-calls.test.ts +183 -189
  121. package/src/wallets/eip5792/send-calls.ts +53 -71
  122. package/src/wallets/in-app/core/{eip5972 → eip5792}/in-app-wallet-calls.ts +4 -8
  123. package/src/wallets/in-app/core/eip7702/minimal-account.ts +666 -5
  124. package/src/wallets/in-app/core/wallet/enclave-wallet.ts +36 -1
  125. package/src/wallets/injected/index.ts +63 -0
  126. package/src/wallets/interfaces/wallet.ts +31 -0
  127. package/src/wallets/smart/index.ts +69 -1
  128. package/src/wallets/wallet-connect/controller.ts +28 -25
  129. package/dist/cjs/wallets/in-app/core/eip5972/in-app-wallet-calls.js.map +0 -1
  130. package/dist/cjs/wallets/in-app/core/eip5972/in-app-wallet-capabilities.js +0 -41
  131. package/dist/cjs/wallets/in-app/core/eip5972/in-app-wallet-capabilities.js.map +0 -1
  132. package/dist/cjs/wallets/smart/lib/smart-wallet-capabilities.js +0 -30
  133. package/dist/cjs/wallets/smart/lib/smart-wallet-capabilities.js.map +0 -1
  134. package/dist/esm/wallets/in-app/core/eip5972/in-app-wallet-calls.js.map +0 -1
  135. package/dist/esm/wallets/in-app/core/eip5972/in-app-wallet-capabilities.js +0 -38
  136. package/dist/esm/wallets/in-app/core/eip5972/in-app-wallet-capabilities.js.map +0 -1
  137. package/dist/esm/wallets/smart/lib/smart-wallet-capabilities.js +0 -27
  138. package/dist/esm/wallets/smart/lib/smart-wallet-capabilities.js.map +0 -1
  139. package/dist/types/wallets/in-app/core/eip5972/in-app-wallet-calls.d.ts.map +0 -1
  140. package/dist/types/wallets/in-app/core/eip5972/in-app-wallet-capabilities.d.ts +0 -20
  141. package/dist/types/wallets/in-app/core/eip5972/in-app-wallet-capabilities.d.ts.map +0 -1
  142. package/dist/types/wallets/smart/lib/smart-wallet-capabilities.d.ts +0 -20
  143. package/dist/types/wallets/smart/lib/smart-wallet-capabilities.d.ts.map +0 -1
  144. package/src/wallets/in-app/core/eip5972/in-app-wallet-capabilities.ts +0 -47
  145. package/src/wallets/smart/lib/smart-wallet-capabilities.ts +0 -32
@@ -1,14 +1,5 @@
1
- import { getAddress } from "../../utils/address.js";
2
1
  import type { Prettify } from "../../utils/type-utils.js";
3
- import {
4
- type CoinbaseWalletCreationOptions,
5
- isCoinbaseSDKWallet,
6
- } from "../coinbase/coinbase-web.js";
7
- import { isInAppWallet } from "../in-app/core/wallet/index.js";
8
- import { getInjectedProvider } from "../injected/index.js";
9
- import type { Ethereum } from "../interfaces/ethereum.js";
10
2
  import type { Wallet } from "../interfaces/wallet.js";
11
- import { isWalletConnect } from "../wallet-connect/controller.js";
12
3
  import type { WalletId } from "../wallet-types.js";
13
4
  import type { WalletCapabilities, WalletCapabilitiesRecord } from "./types.js";
14
5
 
@@ -52,64 +43,32 @@ export async function getCapabilities<const ID extends WalletId = WalletId>({
52
43
  };
53
44
  }
54
45
 
55
- if (wallet.id === "smart") {
56
- const { smartWalletGetCapabilities } = await import(
57
- "../smart/lib/smart-wallet-capabilities.js"
58
- );
59
- return smartWalletGetCapabilities({ wallet });
46
+ if (account.getCapabilities) {
47
+ return account.getCapabilities({ chainId });
60
48
  }
61
49
 
62
- if (isInAppWallet(wallet)) {
63
- const { inAppWalletGetCapabilities } = await import(
64
- "../in-app/core/eip5972/in-app-wallet-capabilities.js"
65
- );
66
- return inAppWalletGetCapabilities({ wallet });
67
- }
68
-
69
- // TODO: Add Wallet Connect support
70
- if (isWalletConnect(wallet)) {
71
- return {
72
- message: "getCapabilities is not yet supported with Wallet Connect",
73
- };
74
- }
75
-
76
- let provider: Ethereum;
77
- if (isCoinbaseSDKWallet(wallet)) {
78
- const { getCoinbaseWebProvider } = await import(
79
- "../coinbase/coinbase-web.js"
80
- );
81
- const config = wallet.getConfig() as CoinbaseWalletCreationOptions;
82
- provider = (await getCoinbaseWebProvider(config)) as Ethereum;
83
- } else {
84
- provider = getInjectedProvider(wallet.id);
85
- }
50
+ throw new Error(
51
+ `Failed to get capabilities, wallet ${wallet.id} does not support EIP-5792`,
52
+ );
53
+ }
86
54
 
87
- try {
88
- const result = await provider.request({
89
- method: "wallet_getCapabilities",
90
- params: [getAddress(account.address)],
91
- });
92
- const capabilities = {} as WalletCapabilitiesRecord<
93
- WalletCapabilities,
94
- number
95
- >;
96
- for (const [chainId, capabilities_] of Object.entries(result)) {
97
- capabilities[Number(chainId)] = {};
98
- const capabilitiesCopy = {} as WalletCapabilities;
99
- for (const [key, value] of Object.entries(capabilities_)) {
100
- capabilitiesCopy[key] = value;
101
- }
102
- capabilities[Number(chainId)] = capabilitiesCopy;
103
- }
104
- return (
105
- typeof chainId === "number" ? capabilities[chainId] : capabilities
106
- ) as never;
107
- } catch (error: unknown) {
108
- if (/unsupport|not support|not available/i.test((error as Error).message)) {
109
- return {
110
- message: `${wallet.id} does not support wallet_getCapabilities, reach out to them directly to request EIP-5792 support.`,
111
- };
55
+ export function toGetCapabilitiesResult(
56
+ result: Record<string, WalletCapabilities>,
57
+ chainId?: number,
58
+ ): GetCapabilitiesResult {
59
+ const capabilities = {} as WalletCapabilitiesRecord<
60
+ WalletCapabilities,
61
+ number
62
+ >;
63
+ for (const [chainId, capabilities_] of Object.entries(result)) {
64
+ capabilities[Number(chainId)] = {};
65
+ const capabilitiesCopy = {} as WalletCapabilities;
66
+ for (const [key, value] of Object.entries(capabilities_)) {
67
+ capabilitiesCopy[key] = value;
112
68
  }
113
- throw error;
69
+ capabilities[Number(chainId)] = capabilitiesCopy;
114
70
  }
71
+ return (
72
+ typeof chainId === "number" ? capabilities[chainId] : capabilities
73
+ ) as never;
115
74
  }
@@ -1,20 +1,15 @@
1
1
  import { afterEach } from "node:test";
2
- import { beforeAll, describe, expect, test, vi } from "vitest";
2
+ import { describe, expect, test, vi } from "vitest";
3
3
  import {
4
4
  ANVIL_CHAIN,
5
5
  FORKED_ETHEREUM_CHAIN,
6
6
  } from "../../../test/src/chains.js";
7
7
  import { TEST_CLIENT } from "../../../test/src/test-clients.js";
8
- import { USDT_CONTRACT } from "../../../test/src/test-contracts.js";
9
- import {
10
- TEST_ACCOUNT_A,
11
- TEST_ACCOUNT_B,
12
- TEST_ACCOUNT_C,
13
- } from "../../../test/src/test-wallets.js";
8
+ import { TEST_ACCOUNT_A } from "../../../test/src/test-wallets.js";
14
9
  import { sepolia } from "../../exports/chains.js";
15
- import { approve } from "../../exports/extensions/erc20.js";
16
10
  import { prepareTransaction } from "../../transaction/prepare-transaction.js";
17
11
  import { numberToHex } from "../../utils/encoding/hex.js";
12
+ import { stringify } from "../../utils/json.js";
18
13
  import { METAMASK } from "../constants.js";
19
14
  import { createWallet } from "../create-wallet.js";
20
15
  import type { Wallet } from "../interfaces/wallet.js";
@@ -35,167 +30,153 @@ const SEND_CALLS_OPTIONS: Omit<SendCallsOptions, "wallet"> = {
35
30
  ),
36
31
  };
37
32
 
38
- const RAW_UNSUPPORTED_ERROR = {
39
- code: -32601,
40
- message: "some nonsense the wallet sends us about not supporting",
41
- };
42
-
43
33
  const mocks = vi.hoisted(() => ({
44
- eth_estimateGas: vi.fn(),
45
- injectedRequest: vi.fn(),
46
- sendAndConfirmTransaction: vi.fn(),
47
- sendBatchTransaction: vi.fn(),
34
+ sendCalls: vi.fn(),
35
+ inAppWalletSendCalls: vi.fn(),
48
36
  }));
49
37
 
50
- vi.mock("../injected/index.js", () => {
38
+ // Mock the in-app wallet calls implementation
39
+ vi.mock("../in-app/core/eip5792/in-app-wallet-calls.js", () => {
51
40
  return {
52
- getInjectedProvider: vi.fn().mockReturnValue({
53
- request: mocks.injectedRequest,
54
- }),
41
+ inAppWalletSendCalls: mocks.inAppWalletSendCalls,
55
42
  };
56
43
  });
57
44
 
58
- vi.mock("../../transaction/actions/send-and-confirm-transaction.js", () => {
59
- return {
60
- sendAndConfirmTransaction:
61
- mocks.sendAndConfirmTransaction.mockResolvedValue({
62
- transactionHash:
63
- "0x9b7bb827c2e5e3c1a0a44dc53e573aa0b3af3bd1f9f5ed03071b100bb039eaff",
64
- }),
65
- };
66
- });
67
-
68
- vi.mock("../../transaction/actions/send-batch-transaction.js", () => {
69
- return {
70
- sendBatchTransaction: mocks.sendBatchTransaction.mockResolvedValue({
71
- transactionHash:
72
- "0x9b7bb827c2e5e3c1a0a44dc53e573aa0b3af3bd1f9f5ed03071b100bb039eaff",
73
- }),
74
- };
75
- });
76
-
77
- describe.sequential("injected wallet", () => {
45
+ describe.sequential("sendCalls general", () => {
78
46
  const wallet: Wallet = createWallet(METAMASK);
79
47
 
80
- beforeAll(() => {
81
- mocks.injectedRequest.mockResolvedValue("0x123456");
82
- });
83
-
84
48
  afterEach(() => {
85
49
  vi.clearAllMocks();
86
50
  });
87
51
 
88
- test("with no chain should fail to send calls", async () => {
89
- wallet.getChain = vi.fn().mockReturnValue(undefined);
90
- wallet.getAccount = vi.fn().mockReturnValue(TEST_ACCOUNT_A);
52
+ test("with no account should fail to send calls", async () => {
53
+ wallet.getChain = vi.fn().mockReturnValue(ANVIL_CHAIN);
54
+ wallet.getAccount = vi.fn().mockReturnValue(undefined);
91
55
 
92
56
  const promise = sendCalls({ wallet, ...SEND_CALLS_OPTIONS });
93
57
  await expect(promise).rejects.toMatchInlineSnapshot(
94
- "[Error: Cannot send calls, no active chain found for wallet: io.metamask]",
58
+ "[Error: Cannot send calls, no account connected for wallet: io.metamask]",
95
59
  );
96
60
  });
97
61
 
98
- test("with no account should fail to send calls", async () => {
62
+ test("without sendCalls support should fail", async () => {
99
63
  wallet.getChain = vi.fn().mockReturnValue(ANVIL_CHAIN);
100
- wallet.getAccount = vi.fn().mockReturnValue(undefined);
64
+ wallet.getAccount = vi.fn().mockReturnValue({
65
+ ...TEST_ACCOUNT_A,
66
+ // no sendCalls method
67
+ });
101
68
 
102
69
  const promise = sendCalls({ wallet, ...SEND_CALLS_OPTIONS });
103
70
  await expect(promise).rejects.toMatchInlineSnapshot(
104
- "[Error: Cannot send calls, no account connected for wallet: io.metamask]",
71
+ "[Error: Cannot send calls, wallet io.metamask does not support EIP-5792]",
105
72
  );
106
73
  });
107
74
 
108
- test("should send calls", async () => {
75
+ test("should delegate to account.sendCalls", async () => {
76
+ const mockAccount = {
77
+ ...TEST_ACCOUNT_A,
78
+ sendCalls: mocks.sendCalls.mockResolvedValue({
79
+ id: "0x123456",
80
+ client: TEST_CLIENT,
81
+ chain: ANVIL_CHAIN,
82
+ }),
83
+ };
84
+
109
85
  wallet.getChain = vi.fn().mockReturnValue(ANVIL_CHAIN);
110
- wallet.getAccount = vi.fn().mockReturnValue(TEST_ACCOUNT_A);
86
+ wallet.getAccount = vi.fn().mockReturnValue(mockAccount);
111
87
 
112
88
  const result = await sendCalls({ wallet, ...SEND_CALLS_OPTIONS });
113
89
 
114
90
  expect(result.id).toEqual("0x123456");
115
- expect(mocks.injectedRequest).toHaveBeenCalledWith({
116
- method: "wallet_sendCalls",
117
- params: [
118
- {
119
- atomicRequired: false,
120
- calls: [
121
- {
122
- data: "0xabcdef",
123
- to: "0x2a4f24F935Eb178e3e7BA9B53A5Ee6d8407C0709",
124
- value: undefined,
125
- },
126
- {
127
- data: "0x",
128
- to: "0xa922b54716264130634d6ff183747a8ead91a40b",
129
- value: numberToHex(123n),
130
- },
131
- ],
132
- capabilities: undefined,
133
- chainId: numberToHex(ANVIL_CHAIN.id),
134
- from: TEST_ACCOUNT_A.address,
135
- version: "2.0.0",
136
- },
137
- ],
91
+ expect(result.wallet).toBe(wallet);
92
+ expect(mocks.sendCalls).toHaveBeenCalledWith({
93
+ calls: SEND_CALLS_OPTIONS.calls,
138
94
  });
139
95
  });
140
96
 
141
- test("should send calls from prepared contract call", async () => {
142
- wallet.getChain = vi.fn().mockReturnValue(FORKED_ETHEREUM_CHAIN);
143
- wallet.getAccount = vi.fn().mockReturnValue(TEST_ACCOUNT_A);
144
-
145
- const preparedTx = approve({
146
- amount: 100,
147
- contract: USDT_CONTRACT,
148
- spender: TEST_ACCOUNT_B.address,
149
- });
150
- const preparedTx2 = approve({
151
- amount: 100,
152
- contract: USDT_CONTRACT,
153
- spender: TEST_ACCOUNT_C.address,
154
- });
97
+ test("should switch chain if needed", async () => {
98
+ const mockAccount = {
99
+ ...TEST_ACCOUNT_A,
100
+ sendCalls: mocks.sendCalls.mockResolvedValue({
101
+ id: "0x123456",
102
+ client: TEST_CLIENT,
103
+ chain: sepolia,
104
+ }),
105
+ };
155
106
 
156
- const result = await sendCalls({
157
- calls: [preparedTx, preparedTx2],
158
- chain: ANVIL_CHAIN,
159
- wallet,
160
- });
107
+ const switchChainMock = vi.fn();
108
+ wallet.getChain = vi.fn().mockReturnValue(ANVIL_CHAIN);
109
+ wallet.getAccount = vi.fn().mockReturnValue(mockAccount);
110
+ wallet.switchChain = switchChainMock;
161
111
 
162
- expect(result.id).toEqual("0x123456");
163
- expect(mocks.injectedRequest).toHaveBeenCalledWith({
164
- method: "wallet_sendCalls",
165
- params: [
112
+ // Create calls with sepolia chain to trigger chain switch
113
+ const sepoliaCallsOptions = {
114
+ calls: [
166
115
  {
167
- atomicRequired: false,
168
- calls: [
169
- {
170
- data: "0x095ea7b300000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c80000000000000000000000000000000000000000000000000000000005f5e100",
171
- to: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
172
- value: undefined,
173
- },
116
+ data: "0xabcdef" as const,
117
+ to: "0x2a4f24F935Eb178e3e7BA9B53A5Ee6d8407C0709",
118
+ },
119
+ ].map((call) =>
120
+ prepareTransaction({ ...call, chain: sepolia, client: TEST_CLIENT }),
121
+ ),
122
+ };
123
+
124
+ await sendCalls({ wallet, ...sepoliaCallsOptions });
125
+
126
+ expect(switchChainMock).toHaveBeenCalledWith(sepolia);
127
+ });
128
+ });
129
+
130
+ describe.sequential("injected wallet account.sendCalls", () => {
131
+ // These tests verify the behavior of the sendCalls method on injected wallet accounts
132
+ // The actual implementation is in packages/thirdweb/src/wallets/injected/index.ts
133
+
134
+ test("should handle successful sendCalls", async () => {
135
+ const mockProvider = {
136
+ request: vi.fn().mockResolvedValue("0x123456"),
137
+ };
138
+
139
+ // Mock what an injected account with sendCalls would look like
140
+ const injectedAccount = {
141
+ ...TEST_ACCOUNT_A,
142
+ sendCalls: async (_options: SendCallsOptions) => {
143
+ // This mimics the implementation in injected/index.ts
144
+ const callId = await mockProvider.request({
145
+ method: "wallet_sendCalls",
146
+ params: [
174
147
  {
175
- data: "0x095ea7b30000000000000000000000003c44cdddb6a900fa2b585dd299e03d12fa4293bc0000000000000000000000000000000000000000000000000000000005f5e100",
176
- to: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
177
- value: undefined,
148
+ atomicRequired: false,
149
+ calls: [
150
+ {
151
+ data: "0xabcdef",
152
+ to: "0x2a4f24F935Eb178e3e7BA9B53A5Ee6d8407C0709",
153
+ value: undefined,
154
+ },
155
+ {
156
+ data: "0x",
157
+ to: "0xa922b54716264130634d6ff183747a8ead91a40b",
158
+ value: numberToHex(123n),
159
+ },
160
+ ],
161
+ capabilities: undefined,
162
+ chainId: numberToHex(ANVIL_CHAIN.id),
163
+ from: TEST_ACCOUNT_A.address,
164
+ version: "2.0.0",
178
165
  },
179
166
  ],
180
- capabilities: undefined,
181
- chainId: numberToHex(ANVIL_CHAIN.id),
182
- from: TEST_ACCOUNT_A.address,
183
- version: "2.0.0",
184
- },
185
- ],
186
- });
187
- });
167
+ });
168
+ return { id: callId, client: TEST_CLIENT, chain: ANVIL_CHAIN };
169
+ },
170
+ };
188
171
 
189
- test("should override chainId", async () => {
172
+ const wallet: Wallet = createWallet(METAMASK);
190
173
  wallet.getChain = vi.fn().mockReturnValue(ANVIL_CHAIN);
191
- const result = await sendCalls({
192
- chain: sepolia,
193
- wallet,
194
- ...SEND_CALLS_OPTIONS,
195
- });
174
+ wallet.getAccount = vi.fn().mockReturnValue(injectedAccount);
175
+
176
+ const result = await sendCalls({ wallet, ...SEND_CALLS_OPTIONS });
196
177
 
197
178
  expect(result.id).toEqual("0x123456");
198
- expect(mocks.injectedRequest).toHaveBeenCalledWith({
179
+ expect(mockProvider.request).toHaveBeenCalledWith({
199
180
  method: "wallet_sendCalls",
200
181
  params: [
201
182
  {
@@ -213,7 +194,7 @@ describe.sequential("injected wallet", () => {
213
194
  },
214
195
  ],
215
196
  capabilities: undefined,
216
- chainId: numberToHex(sepolia.id),
197
+ chainId: numberToHex(ANVIL_CHAIN.id),
217
198
  from: TEST_ACCOUNT_A.address,
218
199
  version: "2.0.0",
219
200
  },
@@ -221,14 +202,39 @@ describe.sequential("injected wallet", () => {
221
202
  });
222
203
  });
223
204
 
224
- test("without support should fail", async () => {
225
- mocks.injectedRequest.mockRejectedValue(RAW_UNSUPPORTED_ERROR);
226
- wallet.getAccount = vi.fn().mockReturnValue(TEST_ACCOUNT_A);
205
+ test("should handle provider errors", async () => {
206
+ const mockProvider = {
207
+ request: vi.fn().mockRejectedValue({
208
+ code: -32601,
209
+ message: "some nonsense the wallet sends us about not supporting",
210
+ }),
211
+ };
212
+
213
+ const injectedAccount = {
214
+ ...TEST_ACCOUNT_A,
215
+ sendCalls: async (_options: SendCallsOptions) => {
216
+ try {
217
+ const callId = await mockProvider.request({
218
+ method: "wallet_sendCalls",
219
+ params: [],
220
+ });
221
+ return { id: callId, client: TEST_CLIENT, chain: ANVIL_CHAIN };
222
+ } catch (error) {
223
+ if (/unsupport|not support/i.test((error as Error).message)) {
224
+ throw new Error(
225
+ `io.metamask errored calling wallet_sendCalls, with error: ${stringify(error)}`,
226
+ );
227
+ }
228
+ throw error;
229
+ }
230
+ },
231
+ };
232
+
233
+ const wallet: Wallet = createWallet(METAMASK);
227
234
  wallet.getChain = vi.fn().mockReturnValue(ANVIL_CHAIN);
228
- const promise = sendCalls({
229
- wallet,
230
- ...SEND_CALLS_OPTIONS,
231
- });
235
+ wallet.getAccount = vi.fn().mockReturnValue(injectedAccount);
236
+
237
+ const promise = sendCalls({ wallet, ...SEND_CALLS_OPTIONS });
232
238
 
233
239
  await expect(promise).rejects.toMatchInlineSnapshot(
234
240
  `[Error: io.metamask errored calling wallet_sendCalls, with error: {"code":-32601,"message":"some nonsense the wallet sends us about not supporting"}]`,
@@ -237,27 +243,37 @@ describe.sequential("injected wallet", () => {
237
243
  });
238
244
 
239
245
  describe.sequential("in-app wallet", () => {
240
- let wallet: Wallet = createWallet("inApp");
246
+ const wallet: Wallet = createWallet("inApp");
241
247
 
242
248
  afterEach(() => {
243
249
  vi.clearAllMocks();
244
250
  });
245
251
 
246
- test("should send individual calls", async () => {
247
- wallet.getChain = vi.fn().mockReturnValue(ANVIL_CHAIN);
248
- wallet.getAccount = vi.fn().mockReturnValue(TEST_ACCOUNT_A);
252
+ test("should send calls via inAppWalletSendCalls", async () => {
253
+ // Configure the mock to return the expected value
254
+ mocks.inAppWalletSendCalls.mockResolvedValue("0x789abc");
249
255
 
250
- await sendCalls({ wallet, ...SEND_CALLS_OPTIONS });
256
+ const inAppAccount = {
257
+ ...TEST_ACCOUNT_A,
258
+ sendCalls: async (options: SendCallsOptions) => {
259
+ const id = await mocks.inAppWalletSendCalls({
260
+ account: inAppAccount,
261
+ calls: options.calls,
262
+ });
263
+ return { id, client: TEST_CLIENT, chain: ANVIL_CHAIN };
264
+ },
265
+ };
251
266
 
252
- expect(mocks.sendAndConfirmTransaction).toHaveBeenCalledTimes(2);
253
- });
267
+ wallet.getChain = vi.fn().mockReturnValue(ANVIL_CHAIN);
268
+ wallet.getAccount = vi.fn().mockReturnValue(inAppAccount);
254
269
 
255
- test("without account should fail", async () => {
256
- wallet.getAccount = vi.fn().mockReturnValue(undefined);
257
- const promise = sendCalls({ wallet, ...SEND_CALLS_OPTIONS });
258
- await expect(promise).rejects.toMatchInlineSnapshot(
259
- "[Error: Cannot send calls, no account connected for wallet: inApp]",
260
- );
270
+ const result = await sendCalls({ wallet, ...SEND_CALLS_OPTIONS });
271
+
272
+ expect(result.id).toEqual("0x789abc");
273
+ expect(mocks.inAppWalletSendCalls).toHaveBeenCalledWith({
274
+ account: inAppAccount,
275
+ calls: SEND_CALLS_OPTIONS.calls,
276
+ });
261
277
  });
262
278
 
263
279
  test("without account should fail", async () => {
@@ -267,21 +283,6 @@ describe.sequential("in-app wallet", () => {
267
283
  "[Error: Cannot send calls, no account connected for wallet: inApp]",
268
284
  );
269
285
  });
270
-
271
- test("with smart account should send batch calls", async () => {
272
- wallet = createWallet("inApp", {
273
- smartAccount: { chain: FORKED_ETHEREUM_CHAIN, sponsorGas: true },
274
- });
275
- wallet.getChain = vi.fn().mockReturnValue(FORKED_ETHEREUM_CHAIN);
276
- wallet.getAccount = vi.fn().mockReturnValue({
277
- ...TEST_ACCOUNT_A,
278
- sendBatchTransaction: vi.fn(), // must specify this to make it behave like a smart account without connecting
279
- });
280
-
281
- await sendCalls({ wallet, ...SEND_CALLS_OPTIONS });
282
-
283
- expect(mocks.sendBatchTransaction).toHaveBeenCalledTimes(1);
284
- });
285
286
  });
286
287
 
287
288
  describe.sequential("smart wallet", () => {
@@ -289,44 +290,37 @@ describe.sequential("smart wallet", () => {
289
290
  chain: FORKED_ETHEREUM_CHAIN,
290
291
  sponsorGas: true,
291
292
  });
292
- wallet.getAccount = vi.fn().mockReturnValue({
293
- ...TEST_ACCOUNT_A,
294
- sendBatchTransaction: vi.fn(), // must specify this to make it behave like a smart account without connecting
295
- });
296
293
 
297
294
  afterEach(() => {
298
295
  vi.clearAllMocks();
299
296
  });
300
297
 
301
- test("should send batch calls", async () => {
302
- wallet.getChain = vi.fn().mockReturnValue(ANVIL_CHAIN);
303
-
304
- await sendCalls({ wallet, ...SEND_CALLS_OPTIONS });
298
+ test("should send calls via inAppWalletSendCalls", async () => {
299
+ // Configure the mock to return the expected value
300
+ mocks.inAppWalletSendCalls.mockResolvedValue("0x789abc");
305
301
 
306
- expect(mocks.sendBatchTransaction).toHaveBeenCalledTimes(1);
307
- });
308
- });
309
-
310
- describe.sequential("smart wallet", () => {
311
- const wallet: Wallet = createWallet("smart", {
312
- chain: FORKED_ETHEREUM_CHAIN,
313
- sponsorGas: true,
314
- });
315
-
316
- afterEach(() => {
317
- vi.clearAllMocks();
318
- });
302
+ const smartAccount = {
303
+ ...TEST_ACCOUNT_A,
304
+ sendBatchTransaction: vi.fn(),
305
+ sendCalls: async (options: SendCallsOptions) => {
306
+ const id = await mocks.inAppWalletSendCalls({
307
+ account: smartAccount,
308
+ calls: options.calls,
309
+ });
310
+ return { id, client: TEST_CLIENT, chain: ANVIL_CHAIN };
311
+ },
312
+ };
319
313
 
320
- test("should send batch transacition", async () => {
321
314
  wallet.getChain = vi.fn().mockReturnValue(ANVIL_CHAIN);
322
- wallet.getAccount = vi.fn().mockReturnValue({
323
- ...TEST_ACCOUNT_A,
324
- sendBatchTransaction: vi.fn(), // we have to mock this because it doesn't get set until the wallet is connected
325
- });
315
+ wallet.getAccount = vi.fn().mockReturnValue(smartAccount);
326
316
 
327
- await sendCalls({ wallet, ...SEND_CALLS_OPTIONS });
317
+ const result = await sendCalls({ wallet, ...SEND_CALLS_OPTIONS });
328
318
 
329
- expect(mocks.sendBatchTransaction).toHaveBeenCalledTimes(1);
319
+ expect(result.id).toEqual("0x789abc");
320
+ expect(mocks.inAppWalletSendCalls).toHaveBeenCalledWith({
321
+ account: smartAccount,
322
+ calls: SEND_CALLS_OPTIONS.calls,
323
+ });
330
324
  });
331
325
  });
332
326