thirdweb 5.65.1 → 5.66.0-nightly-880c3453ee8fc0fabbde0afb752a17894cd579a0-20241106000325

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 (89) hide show
  1. package/dist/cjs/chains/utils.js +14 -6
  2. package/dist/cjs/chains/utils.js.map +1 -1
  3. package/dist/cjs/exports/react.js +4 -1
  4. package/dist/cjs/exports/react.js.map +1 -1
  5. package/dist/cjs/extensions/erc20/write/transferBatch.js +65 -18
  6. package/dist/cjs/extensions/erc20/write/transferBatch.js.map +1 -1
  7. package/dist/cjs/react/core/hooks/contract/useContractEvents.js +1 -1
  8. package/dist/cjs/react/core/hooks/contract/useContractEvents.js.map +1 -1
  9. package/dist/cjs/react/core/hooks/wallets/useAutoConnect.js +19 -2
  10. package/dist/cjs/react/core/hooks/wallets/useAutoConnect.js.map +1 -1
  11. package/dist/cjs/react/native/ui/connect/ConnectModal.js.map +1 -1
  12. package/dist/cjs/react/native/ui/connect/ConnectedModal.js.map +1 -1
  13. package/dist/cjs/react/web/ui/ConnectWallet/Details.js.map +1 -1
  14. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js +1 -1
  15. package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js.map +1 -1
  16. package/dist/cjs/react/web/ui/MediaRenderer/ModelViewer.js +3 -1
  17. package/dist/cjs/react/web/ui/MediaRenderer/ModelViewer.js.map +1 -1
  18. package/dist/cjs/react/web/ui/SiteEmbed.js +63 -0
  19. package/dist/cjs/react/web/ui/SiteEmbed.js.map +1 -0
  20. package/dist/cjs/react/web/wallets/in-app/WalletAuth.js +1 -1
  21. package/dist/cjs/react/web/wallets/in-app/WalletAuth.js.map +1 -1
  22. package/dist/cjs/version.js +1 -1
  23. package/dist/cjs/version.js.map +1 -1
  24. package/dist/cjs/wallets/in-app/web/lib/get-url-token.js +10 -4
  25. package/dist/cjs/wallets/in-app/web/lib/get-url-token.js.map +1 -1
  26. package/dist/esm/chains/utils.js +8 -2
  27. package/dist/esm/chains/utils.js.map +1 -1
  28. package/dist/esm/exports/react.js +2 -0
  29. package/dist/esm/exports/react.js.map +1 -1
  30. package/dist/esm/extensions/erc20/write/transferBatch.js +64 -18
  31. package/dist/esm/extensions/erc20/write/transferBatch.js.map +1 -1
  32. package/dist/esm/react/core/hooks/contract/useContractEvents.js +1 -1
  33. package/dist/esm/react/core/hooks/contract/useContractEvents.js.map +1 -1
  34. package/dist/esm/react/core/hooks/wallets/useAutoConnect.js +19 -2
  35. package/dist/esm/react/core/hooks/wallets/useAutoConnect.js.map +1 -1
  36. package/dist/esm/react/native/ui/connect/ConnectModal.js.map +1 -1
  37. package/dist/esm/react/native/ui/connect/ConnectedModal.js.map +1 -1
  38. package/dist/esm/react/web/ui/ConnectWallet/Details.js.map +1 -1
  39. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js +1 -1
  40. package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js.map +1 -1
  41. package/dist/esm/react/web/ui/MediaRenderer/ModelViewer.js +3 -1
  42. package/dist/esm/react/web/ui/MediaRenderer/ModelViewer.js.map +1 -1
  43. package/dist/esm/react/web/ui/SiteEmbed.js +60 -0
  44. package/dist/esm/react/web/ui/SiteEmbed.js.map +1 -0
  45. package/dist/esm/react/web/wallets/in-app/WalletAuth.js +1 -1
  46. package/dist/esm/react/web/wallets/in-app/WalletAuth.js.map +1 -1
  47. package/dist/esm/version.js +1 -1
  48. package/dist/esm/version.js.map +1 -1
  49. package/dist/esm/wallets/in-app/web/lib/get-url-token.js +10 -4
  50. package/dist/esm/wallets/in-app/web/lib/get-url-token.js.map +1 -1
  51. package/dist/types/chains/utils.d.ts +10 -0
  52. package/dist/types/chains/utils.d.ts.map +1 -1
  53. package/dist/types/exports/react.d.ts +1 -0
  54. package/dist/types/exports/react.d.ts.map +1 -1
  55. package/dist/types/extensions/erc20/write/transferBatch.d.ts +31 -0
  56. package/dist/types/extensions/erc20/write/transferBatch.d.ts.map +1 -1
  57. package/dist/types/react/core/hooks/connection/ConnectButtonProps.d.ts +1 -0
  58. package/dist/types/react/core/hooks/connection/ConnectButtonProps.d.ts.map +1 -1
  59. package/dist/types/react/core/hooks/wallets/useAutoConnect.d.ts.map +1 -1
  60. package/dist/types/react/web/ui/ConnectWallet/Details.d.ts +1 -0
  61. package/dist/types/react/web/ui/ConnectWallet/Details.d.ts.map +1 -1
  62. package/dist/types/react/web/ui/MediaRenderer/ModelViewer.d.ts +0 -8
  63. package/dist/types/react/web/ui/MediaRenderer/ModelViewer.d.ts.map +1 -1
  64. package/dist/types/react/web/ui/SiteEmbed.d.ts +27 -0
  65. package/dist/types/react/web/ui/SiteEmbed.d.ts.map +1 -0
  66. package/dist/types/react/web/ui/components/Drawer.d.ts +2 -2
  67. package/dist/types/version.d.ts +1 -1
  68. package/dist/types/version.d.ts.map +1 -1
  69. package/dist/types/wallets/in-app/web/lib/get-url-token.d.ts +1 -0
  70. package/dist/types/wallets/in-app/web/lib/get-url-token.d.ts.map +1 -1
  71. package/package.json +29 -29
  72. package/src/chains/utils.test.ts +123 -0
  73. package/src/chains/utils.ts +8 -2
  74. package/src/exports/react.ts +3 -0
  75. package/src/extensions/erc20/write/transferBatch.test.ts +102 -10
  76. package/src/extensions/erc20/write/transferBatch.ts +79 -25
  77. package/src/react/core/hooks/connection/ConnectButtonProps.ts +1 -0
  78. package/src/react/core/hooks/contract/useContractEvents.ts +1 -1
  79. package/src/react/core/hooks/wallets/useAutoConnect.ts +21 -2
  80. package/src/react/native/ui/connect/ConnectModal.tsx +1 -1
  81. package/src/react/native/ui/connect/ConnectedModal.tsx +1 -1
  82. package/src/react/web/ui/ConnectWallet/Details.tsx +1 -1
  83. package/src/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.tsx +2 -1
  84. package/src/react/web/ui/MediaRenderer/ModelViewer.tsx +1 -9
  85. package/src/react/web/ui/SiteEmbed.test.tsx +39 -0
  86. package/src/react/web/ui/SiteEmbed.tsx +90 -0
  87. package/src/react/web/wallets/in-app/WalletAuth.tsx +1 -1
  88. package/src/version.ts +1 -1
  89. package/src/wallets/in-app/web/lib/get-url-token.ts +11 -4
@@ -1,4 +1,4 @@
1
- import { describe, expect, it } from "vitest";
1
+ import { beforeAll, describe, expect, it } from "vitest";
2
2
  import { ANVIL_CHAIN } from "~test/chains.js";
3
3
  import { TEST_CONTRACT_URI } from "~test/ipfs-uris.js";
4
4
  import { TEST_CLIENT } from "~test/test-clients.js";
@@ -8,19 +8,23 @@ import {
8
8
  TEST_ACCOUNT_C,
9
9
  TEST_ACCOUNT_D,
10
10
  } from "~test/test-wallets.js";
11
- import { getContract } from "../../../contract/contract.js";
11
+ import {
12
+ type ThirdwebContract,
13
+ getContract,
14
+ } from "../../../contract/contract.js";
12
15
  import { deployERC20Contract } from "../../../extensions/prebuilts/deploy-erc20.js";
13
16
  import { sendAndConfirmTransaction } from "../../../transaction/actions/send-and-confirm-transaction.js";
14
17
  import { balanceOf } from "../__generated__/IERC20/read/balanceOf.js";
15
18
  import { mintTo } from "./mintTo.js";
16
- import { transferBatch } from "./transferBatch.js";
19
+ import { optimizeTransferContent, transferBatch } from "./transferBatch.js";
17
20
 
18
21
  const chain = ANVIL_CHAIN;
19
22
  const client = TEST_CLIENT;
20
23
  const account = TEST_ACCOUNT_A;
24
+ let contract: ThirdwebContract;
21
25
 
22
26
  describe.runIf(process.env.TW_SECRET_KEY)("erc20: transferBatch", () => {
23
- it("should transfer tokens to multiple recipients", async () => {
27
+ beforeAll(async () => {
24
28
  const address = await deployERC20Contract({
25
29
  type: "TokenERC20",
26
30
  account,
@@ -31,15 +35,16 @@ describe.runIf(process.env.TW_SECRET_KEY)("erc20: transferBatch", () => {
31
35
  contractURI: TEST_CONTRACT_URI,
32
36
  },
33
37
  });
34
- const contract = getContract({
38
+ contract = getContract({
35
39
  address,
36
40
  chain,
37
41
  client,
38
42
  });
39
-
40
- // Mint 100 tokens
43
+ }, 60_000_000);
44
+ it("should transfer tokens to multiple recipients", async () => {
45
+ // Mint 200 tokens
41
46
  await sendAndConfirmTransaction({
42
- transaction: mintTo({ contract, to: account.address, amount: 100 }),
47
+ transaction: mintTo({ contract, to: account.address, amount: 200 }),
43
48
  account,
44
49
  });
45
50
 
@@ -61,6 +66,14 @@ describe.runIf(process.env.TW_SECRET_KEY)("erc20: transferBatch", () => {
61
66
  to: TEST_ACCOUNT_D.address,
62
67
  amount: 25,
63
68
  },
69
+ {
70
+ to: TEST_ACCOUNT_B.address.toLowerCase(),
71
+ amount: 25,
72
+ },
73
+ {
74
+ to: TEST_ACCOUNT_B.address,
75
+ amountWei: 25n * 10n ** 18n,
76
+ },
64
77
  ],
65
78
  }),
66
79
  });
@@ -73,9 +86,88 @@ describe.runIf(process.env.TW_SECRET_KEY)("erc20: transferBatch", () => {
73
86
  balanceOf({ contract, address: TEST_ACCOUNT_D.address }),
74
87
  ]);
75
88
 
76
- expect(balanceA).toBe(25n * 10n ** 18n);
77
- expect(balanceB).toBe(25n * 10n ** 18n);
89
+ expect(balanceA).toBe(75n * 10n ** 18n);
90
+ expect(balanceB).toBe(75n * 10n ** 18n);
78
91
  expect(balanceC).toBe(25n * 10n ** 18n);
79
92
  expect(balanceD).toBe(25n * 10n ** 18n);
80
93
  });
94
+
95
+ it("should optimize the transfer content", async () => {
96
+ const content = await optimizeTransferContent({
97
+ contract,
98
+ batch: [
99
+ {
100
+ to: TEST_ACCOUNT_B.address,
101
+ amount: 25,
102
+ },
103
+ {
104
+ to: TEST_ACCOUNT_C.address,
105
+ amount: 25,
106
+ },
107
+ {
108
+ to: TEST_ACCOUNT_D.address,
109
+ amount: 25,
110
+ },
111
+ {
112
+ // Should work
113
+ to: TEST_ACCOUNT_B.address.toLowerCase(),
114
+ amount: 25,
115
+ },
116
+ {
117
+ to: TEST_ACCOUNT_B.address,
118
+ amountWei: 25n * 10n ** 18n,
119
+ },
120
+ ],
121
+ });
122
+
123
+ expect(content).toStrictEqual([
124
+ {
125
+ to: TEST_ACCOUNT_B.address,
126
+ amountWei: 75n * 10n ** 18n,
127
+ },
128
+ {
129
+ to: TEST_ACCOUNT_C.address,
130
+ amountWei: 25n * 10n ** 18n,
131
+ },
132
+ {
133
+ to: TEST_ACCOUNT_D.address,
134
+ amountWei: 25n * 10n ** 18n,
135
+ },
136
+ ]);
137
+ });
138
+
139
+ it("an already-optimized content should not be changed", async () => {
140
+ const content = await optimizeTransferContent({
141
+ contract,
142
+ batch: [
143
+ {
144
+ to: TEST_ACCOUNT_B.address,
145
+ amountWei: 25n * 10n ** 18n,
146
+ },
147
+ {
148
+ to: TEST_ACCOUNT_C.address,
149
+ amount: 25,
150
+ },
151
+ {
152
+ to: TEST_ACCOUNT_D.address,
153
+ amount: 25,
154
+ },
155
+ ],
156
+ });
157
+
158
+ expect(content).toStrictEqual([
159
+ {
160
+ to: TEST_ACCOUNT_B.address,
161
+ amountWei: 25n * 10n ** 18n,
162
+ },
163
+ {
164
+ to: TEST_ACCOUNT_C.address,
165
+ amountWei: 25n * 10n ** 18n,
166
+ },
167
+ {
168
+ to: TEST_ACCOUNT_D.address,
169
+ amountWei: 25n * 10n ** 18n,
170
+ },
171
+ ]);
172
+ });
81
173
  });
@@ -53,34 +53,88 @@ export function transferBatch(
53
53
  return multicall({
54
54
  contract: options.contract,
55
55
  asyncParams: async () => {
56
+ const content = await optimizeTransferContent(options);
56
57
  return {
57
- data: await Promise.all(
58
- options.batch.map(async (transfer) => {
59
- let amount: bigint;
60
- if ("amount" in transfer) {
61
- // if we need to parse the amount from ether to gwei then we pull in the decimals extension
62
- const { decimals } = await import("../read/decimals.js");
63
- // it's OK to call this multiple times because the call is cached
64
- // if this fails we fall back to `18` decimals
65
- const d = await decimals(options).catch(() => 18);
66
- // turn ether into gwei
67
- amount = toUnits(transfer.amount.toString(), d);
68
- } else {
69
- amount = transfer.amountWei;
70
- }
71
- return encodeTransfer({
72
- to: transfer.to,
73
- value: amount,
74
- overrides: {
75
- erc20Value: {
76
- amountWei: amount,
77
- tokenAddress: options.contract.address,
78
- },
58
+ data: content.map((item) => {
59
+ return encodeTransfer({
60
+ to: item.to,
61
+ value: item.amountWei,
62
+ overrides: {
63
+ erc20Value: {
64
+ amountWei: item.amountWei,
65
+ tokenAddress: options.contract.address,
79
66
  },
80
- });
81
- }),
82
- ),
67
+ },
68
+ });
69
+ }),
83
70
  };
84
71
  },
85
72
  });
86
73
  }
74
+
75
+ /**
76
+ * Records with the same recipient (`to`) can be packed into one transaction
77
+ * For example, the data below:
78
+ * ```ts
79
+ * [
80
+ * {
81
+ * to: "wallet-a",
82
+ * amount: 1,
83
+ * },
84
+ * {
85
+ * to: "wallet-A",
86
+ * amountWei: 1000000000000000000n,
87
+ * },
88
+ * ]
89
+ * ```
90
+ *
91
+ * can be packed to:
92
+ * ```ts
93
+ * [
94
+ * {
95
+ * to: "wallet-a",
96
+ * amountWei: 2000000000000000000n,
97
+ * },
98
+ * ]
99
+ * ```
100
+ * @internal
101
+ */
102
+ export async function optimizeTransferContent(
103
+ options: BaseTransactionOptions<TransferBatchParams>,
104
+ ): Promise<Array<{ to: string; amountWei: bigint }>> {
105
+ const groupedRecords = await options.batch.reduce(
106
+ async (accPromise, record) => {
107
+ const acc = await accPromise;
108
+ let amountInWei: bigint;
109
+ if ("amount" in record) {
110
+ // it's OK to call this multiple times because the call is cached
111
+ const { decimals } = await import("../read/decimals.js");
112
+ // if this fails we fall back to `18` decimals
113
+ const d = await decimals(options).catch(() => undefined);
114
+ if (d === undefined) {
115
+ throw new Error(
116
+ `Failed to get the decimals for contract: ${options.contract.address}`,
117
+ );
118
+ }
119
+ amountInWei = toUnits(record.amount.toString(), d);
120
+ } else {
121
+ amountInWei = record.amountWei;
122
+ }
123
+ const existingRecord = acc.find(
124
+ (r) => r.to.toLowerCase() === record.to.toLowerCase(),
125
+ );
126
+ if (existingRecord) {
127
+ existingRecord.amountWei = existingRecord.amountWei + amountInWei;
128
+ } else {
129
+ acc.push({
130
+ to: record.to,
131
+ amountWei: amountInWei,
132
+ });
133
+ }
134
+
135
+ return acc;
136
+ },
137
+ Promise.resolve([] as { to: string; amountWei: bigint }[]),
138
+ );
139
+ return groupedRecords;
140
+ }
@@ -1,3 +1,4 @@
1
+ import type { JSX } from "react";
1
2
  import type { Chain } from "../../../../chains/types.js";
2
3
  import type { ThirdwebClient } from "../../../../client/client.js";
3
4
  import type { BuyWithCryptoStatus } from "../../../../pay/buyWithCrypto/getStatus.js";
@@ -84,7 +84,7 @@ export function useContractEvents<
84
84
  enabled = true,
85
85
  watch = true,
86
86
  } = options;
87
- const latestBlockNumber = useRef<bigint>(); // We use this to keep track of the latest block number when new pollers are spawned
87
+ const latestBlockNumber = useRef<bigint>(undefined); // We use this to keep track of the latest block number when new pollers are spawned
88
88
 
89
89
  const queryClient = useQueryClient();
90
90
 
@@ -2,6 +2,8 @@
2
2
 
3
3
  import { useQuery } from "@tanstack/react-query";
4
4
  import type { AsyncStorage } from "../../../../utils/storage/AsyncStorage.js";
5
+ import { isEcosystemWallet } from "../../../../wallets/ecosystem/is-ecosystem-wallet.js";
6
+ import { ClientScopedStorage } from "../../../../wallets/in-app/core/authentication/client-scoped-storage.js";
5
7
  import { getUrlToken } from "../../../../wallets/in-app/web/lib/get-url-token.js";
6
8
  import type { Wallet } from "../../../../wallets/interfaces/wallet.js";
7
9
  import {
@@ -43,8 +45,25 @@ export function useAutoConnectCore(
43
45
  getStoredActiveWalletId(storage),
44
46
  ]);
45
47
 
46
- const { authResult, walletId, authProvider } = getUrlToken();
47
- if (authResult && walletId) {
48
+ const { authResult, walletId, authProvider, authCookie } = getUrlToken();
49
+ const wallet = wallets.find((w) => w.id === walletId);
50
+
51
+ // If an auth cookie is found and this site supports the wallet, we'll set the auth cookie in the client storage
52
+ if (authCookie && wallet) {
53
+ const clientStorage = new ClientScopedStorage({
54
+ storage,
55
+ clientId: props.client.clientId,
56
+ ecosystem: isEcosystemWallet(wallet)
57
+ ? {
58
+ id: wallet.id,
59
+ partnerId: wallet.getConfig()?.partnerId,
60
+ }
61
+ : undefined,
62
+ });
63
+ await clientStorage.saveAuthCookie(authCookie);
64
+ }
65
+
66
+ if (walletId) {
48
67
  lastActiveWalletId = walletId;
49
68
  lastConnectedWalletIds = lastConnectedWalletIds?.includes(walletId)
50
69
  ? lastConnectedWalletIds
@@ -1,4 +1,4 @@
1
- import { useCallback, useState } from "react";
1
+ import { type JSX, useCallback, useState } from "react";
2
2
  import { Platform, StyleSheet, View } from "react-native";
3
3
  import { SvgXml } from "react-native-svg";
4
4
  import type { Chain } from "../../../../chains/types.js";
@@ -1,4 +1,4 @@
1
- import { useEffect, useState } from "react";
1
+ import { type JSX, useEffect, useState } from "react";
2
2
  import { Linking, StyleSheet, TouchableOpacity, View } from "react-native";
3
3
  import type { ThirdwebClient } from "../../../../client/client.js";
4
4
  import { getContract } from "../../../../contract/contract.js";
@@ -9,7 +9,7 @@ import {
9
9
  TextAlignJustifyIcon,
10
10
  } from "@radix-ui/react-icons";
11
11
  import { useQuery } from "@tanstack/react-query";
12
- import { useContext, useEffect, useState } from "react";
12
+ import { type JSX, useContext, useEffect, useState } from "react";
13
13
  import { trackPayEvent } from "../../../../analytics/track/pay.js";
14
14
  import type { Chain } from "../../../../chains/types.js";
15
15
  import type { ThirdwebClient } from "../../../../client/client.js";
@@ -984,7 +984,8 @@ function SwapScreenContent(props: {
984
984
 
985
985
  const disableContinue =
986
986
  (swapRequired && !quoteQuery.data) || isNotEnoughBalance;
987
- const switchChainRequired = props.payer.chain.id !== fromChain.id;
987
+ const switchChainRequired =
988
+ props.payer.wallet.getChain()?.id !== fromChain.id;
988
989
 
989
990
  // biome-ignore lint/suspicious/noExplicitAny: <explanation>
990
991
  function getErrorMessage(err: any) {
@@ -1,16 +1,7 @@
1
1
  import "@google/model-viewer";
2
- import type { ModelViewerElement } from "@google/model-viewer";
3
2
  import React from "react";
4
3
  import type { MediaRendererProps } from "./types.js";
5
4
 
6
- declare global {
7
- namespace JSX {
8
- interface IntrinsicElements {
9
- "model-viewer": Partial<ModelViewerElement>;
10
- }
11
- }
12
- }
13
-
14
5
  const ModelViewer = /* @__PURE__ */ (() =>
15
6
  React.forwardRef<
16
7
  HTMLDivElement,
@@ -19,6 +10,7 @@ const ModelViewer = /* @__PURE__ */ (() =>
19
10
  return (
20
11
  <div style={{ ...style }} className={className} ref={ref}>
21
12
  {src ? (
13
+ // @ts-expect-error - model-viewer is not a standard HTML element
22
14
  <model-viewer
23
15
  src={src}
24
16
  alt={alt || "3D Model"}
@@ -0,0 +1,39 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { render, waitFor } from "../../../../test/src/react-render.js";
3
+ import { TEST_CLIENT } from "../../../../test/src/test-clients.js";
4
+ import { SiteEmbed } from "./SiteEmbed.js";
5
+
6
+ describe("SiteEmbed", () => {
7
+ it("renders iframe with correct src", () => {
8
+ const testUrl = "https://example.com/";
9
+ const { container } = render(
10
+ <SiteEmbed src={testUrl} client={TEST_CLIENT} />,
11
+ );
12
+
13
+ const iframe = container.querySelector("iframe");
14
+ expect(iframe).toBeTruthy();
15
+ expect(iframe?.src).toBe(testUrl);
16
+ });
17
+
18
+ it("throws error if clientId is not provided", () => {
19
+ const testUrl = "https://example.com/";
20
+ expect(() =>
21
+ // biome-ignore lint/suspicious/noExplicitAny: testing invalid input
22
+ render(<SiteEmbed src={testUrl} client={{} as any} />),
23
+ ).toThrow("The SiteEmbed client must have a clientId");
24
+ });
25
+
26
+ it("adds wallet params to url when wallet is connected", async () => {
27
+ const testUrl = "https://example.com/";
28
+ const { container } = render(
29
+ <SiteEmbed src={testUrl} client={TEST_CLIENT} />,
30
+ {
31
+ setConnectedWallet: true,
32
+ },
33
+ );
34
+
35
+ const iframe = container.querySelector("iframe");
36
+ expect(iframe).toBeTruthy();
37
+ await waitFor(() => expect(iframe?.src).toContain("walletId="));
38
+ });
39
+ });
@@ -0,0 +1,90 @@
1
+ "use client";
2
+ import { useQuery } from "@tanstack/react-query";
3
+ import type { ThirdwebClient } from "../../../client/client.js";
4
+ import { getLastAuthProvider } from "../../../react/core/utils/storage.js";
5
+ import { webLocalStorage } from "../../../utils/storage/webStorage.js";
6
+ import { isEcosystemWallet } from "../../../wallets/ecosystem/is-ecosystem-wallet.js";
7
+ import { ClientScopedStorage } from "../../../wallets/in-app/core/authentication/client-scoped-storage.js";
8
+ import type { Ecosystem } from "../../../wallets/in-app/core/wallet/types.js";
9
+ import { useActiveWallet } from "../../core/hooks/wallets/useActiveWallet.js";
10
+
11
+ /**
12
+ * Embeds another thirdweb-supported site for seamless in-app and ecosystem wallet connection.
13
+ *
14
+ * @note Make sure the embedded site includes <AutoConnect /> and supports frame ancestors, see [here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors) for more information.
15
+ *
16
+ * @note The embedded site must support the connected wallet (ecosystem or in-app).
17
+ *
18
+ * @param {Object} props - The props to pass to the iframe
19
+ * @param {String} props.src - The URL of the site to embed
20
+ * @param {ThirdwebClient} props.client - The client to use for the embedded site
21
+ * @param {Ecosystem} [props.ecosystem] - The ecosystem to use for the embedded site
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * import { SiteEmbed } from "thirdweb/react";
26
+ *
27
+ * <SiteEmbed src="https://thirdweb.com" clientId="thirdweb-client-id" />
28
+ * ```
29
+ */
30
+ export function SiteEmbed({
31
+ src,
32
+ client,
33
+ ecosystem,
34
+ ...props
35
+ }: {
36
+ src: string;
37
+ client: ThirdwebClient;
38
+ ecosystem?: Ecosystem;
39
+ } & React.DetailedHTMLProps<
40
+ React.IframeHTMLAttributes<HTMLIFrameElement>,
41
+ HTMLIFrameElement
42
+ >) {
43
+ if (!client.clientId) {
44
+ throw new Error("The SiteEmbed client must have a clientId");
45
+ }
46
+
47
+ const activeWallet = useActiveWallet();
48
+ const walletId = activeWallet?.id;
49
+
50
+ const {
51
+ data: { authProvider, authCookie } = {},
52
+ } = useQuery({
53
+ queryKey: ["site-embed", walletId, src, client.clientId, ecosystem],
54
+ enabled:
55
+ activeWallet && (isEcosystemWallet(activeWallet) || walletId === "inApp"),
56
+ queryFn: async () => {
57
+ const storage = new ClientScopedStorage({
58
+ storage: webLocalStorage,
59
+ clientId: client.clientId,
60
+ ecosystem,
61
+ });
62
+
63
+ const authProvider = await getLastAuthProvider(webLocalStorage);
64
+ const authCookie = await storage.getAuthCookie();
65
+
66
+ return { authProvider, authCookie };
67
+ },
68
+ });
69
+
70
+ const url = new URL(src);
71
+ if (walletId) {
72
+ url.searchParams.set("walletId", walletId);
73
+ }
74
+ if (authProvider) {
75
+ url.searchParams.set("authProvider", authProvider);
76
+ }
77
+ if (authCookie) {
78
+ url.searchParams.set("authCookie", authCookie);
79
+ }
80
+
81
+ return (
82
+ <iframe
83
+ src={encodeURI(url.toString())}
84
+ width="100%"
85
+ height="100%"
86
+ allowFullScreen
87
+ {...props}
88
+ />
89
+ );
90
+ }
@@ -39,7 +39,7 @@ export function WalletAuth(props: {
39
39
  }) {
40
40
  const { wallet, done } = props;
41
41
  const addConnectedWallet = useAddConnectedWallet();
42
- const walletToConnect = useRef<Wallet>();
42
+ const walletToConnect = useRef<Wallet>(undefined);
43
43
  const [status, setStatus] = useState<"loading" | "error" | "selecting">(
44
44
  "selecting",
45
45
  );
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = "5.65.1";
1
+ export const version = "5.66.0-nightly-880c3453ee8fc0fabbde0afb752a17894cd579a0-20241106000325";
@@ -9,6 +9,7 @@ export function getUrlToken(): {
9
9
  walletId?: WalletId;
10
10
  authResult?: AuthStoredTokenWithCookieReturnType;
11
11
  authProvider?: AuthOption;
12
+ authCookie?: string;
12
13
  } {
13
14
  if (!window?.location) {
14
15
  // Not in web
@@ -20,18 +21,24 @@ export function getUrlToken(): {
20
21
  const authResultString = params.get("authResult");
21
22
  const walletId = params.get("walletId") as WalletId | undefined;
22
23
  const authProvider = params.get("authProvider") as AuthOption | undefined;
24
+ const authCookie = params.get("authCookie") as string | undefined;
23
25
 
24
- if (authResultString && walletId) {
25
- const authResult = JSON.parse(authResultString);
26
- params.delete("authResult");
26
+ if ((authCookie || authResultString) && walletId) {
27
+ const authResult = (() => {
28
+ if (authResultString) {
29
+ params.delete("authResult");
30
+ return JSON.parse(decodeURIComponent(authResultString));
31
+ }
32
+ })();
27
33
  params.delete("walletId");
28
34
  params.delete("authProvider");
35
+ params.delete("authCookie");
29
36
  window.history.pushState(
30
37
  {},
31
38
  "",
32
39
  `${window.location.pathname}?${params.toString()}`,
33
40
  );
34
- return { walletId, authResult, authProvider };
41
+ return { walletId, authResult, authProvider, authCookie };
35
42
  }
36
43
  return {};
37
44
  }