thirdweb 5.76.1 → 5.77.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 (110) hide show
  1. package/dist/cjs/contract/deployment/deploy-with-abi.js +1 -1
  2. package/dist/cjs/contract/deployment/deploy-with-abi.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/prebuilts/deploy-published.js +25 -6
  6. package/dist/cjs/extensions/prebuilts/deploy-published.js.map +1 -1
  7. package/dist/cjs/extensions/prebuilts/process-ref-deployments.js +117 -0
  8. package/dist/cjs/extensions/prebuilts/process-ref-deployments.js.map +1 -0
  9. package/dist/cjs/extensions/thirdweb/write/publish.js +1 -0
  10. package/dist/cjs/extensions/thirdweb/write/publish.js.map +1 -1
  11. package/dist/cjs/react/core/utils/storage.js +4 -3
  12. package/dist/cjs/react/core/utils/storage.js.map +1 -1
  13. package/dist/cjs/react/web/ui/prebuilt/Chain/icon.js +12 -1
  14. package/dist/cjs/react/web/ui/prebuilt/Chain/icon.js.map +1 -1
  15. package/dist/cjs/react/web/ui/prebuilt/Chain/name.js +30 -13
  16. package/dist/cjs/react/web/ui/prebuilt/Chain/name.js.map +1 -1
  17. package/dist/cjs/react/web/ui/prebuilt/NFT/description.js +2 -1
  18. package/dist/cjs/react/web/ui/prebuilt/NFT/description.js.map +1 -1
  19. package/dist/cjs/react/web/ui/prebuilt/NFT/media.js +2 -1
  20. package/dist/cjs/react/web/ui/prebuilt/NFT/media.js.map +1 -1
  21. package/dist/cjs/react/web/ui/prebuilt/NFT/name.js +2 -1
  22. package/dist/cjs/react/web/ui/prebuilt/NFT/name.js.map +1 -1
  23. package/dist/cjs/react/web/ui/prebuilt/Token/icon.js +13 -1
  24. package/dist/cjs/react/web/ui/prebuilt/Token/icon.js.map +1 -1
  25. package/dist/cjs/react/web/ui/prebuilt/Token/name.js +57 -26
  26. package/dist/cjs/react/web/ui/prebuilt/Token/name.js.map +1 -1
  27. package/dist/cjs/react/web/ui/prebuilt/Token/symbol.js +57 -26
  28. package/dist/cjs/react/web/ui/prebuilt/Token/symbol.js.map +1 -1
  29. package/dist/cjs/react/web/utils/storage.js +26 -0
  30. package/dist/cjs/react/web/utils/storage.js.map +1 -0
  31. package/dist/cjs/version.js +1 -1
  32. package/dist/esm/contract/deployment/deploy-with-abi.js +1 -1
  33. package/dist/esm/contract/deployment/deploy-with-abi.js.map +1 -1
  34. package/dist/esm/exports/react.js +2 -0
  35. package/dist/esm/exports/react.js.map +1 -1
  36. package/dist/esm/extensions/prebuilts/deploy-published.js +25 -6
  37. package/dist/esm/extensions/prebuilts/deploy-published.js.map +1 -1
  38. package/dist/esm/extensions/prebuilts/process-ref-deployments.js +114 -0
  39. package/dist/esm/extensions/prebuilts/process-ref-deployments.js.map +1 -0
  40. package/dist/esm/extensions/thirdweb/write/publish.js +1 -0
  41. package/dist/esm/extensions/thirdweb/write/publish.js.map +1 -1
  42. package/dist/esm/react/core/utils/storage.js +1 -1
  43. package/dist/esm/react/core/utils/storage.js.map +1 -1
  44. package/dist/esm/react/web/ui/prebuilt/Chain/icon.js +12 -1
  45. package/dist/esm/react/web/ui/prebuilt/Chain/icon.js.map +1 -1
  46. package/dist/esm/react/web/ui/prebuilt/Chain/name.js +29 -13
  47. package/dist/esm/react/web/ui/prebuilt/Chain/name.js.map +1 -1
  48. package/dist/esm/react/web/ui/prebuilt/NFT/description.js +2 -1
  49. package/dist/esm/react/web/ui/prebuilt/NFT/description.js.map +1 -1
  50. package/dist/esm/react/web/ui/prebuilt/NFT/media.js +2 -1
  51. package/dist/esm/react/web/ui/prebuilt/NFT/media.js.map +1 -1
  52. package/dist/esm/react/web/ui/prebuilt/NFT/name.js +2 -1
  53. package/dist/esm/react/web/ui/prebuilt/NFT/name.js.map +1 -1
  54. package/dist/esm/react/web/ui/prebuilt/Token/icon.js +13 -1
  55. package/dist/esm/react/web/ui/prebuilt/Token/icon.js.map +1 -1
  56. package/dist/esm/react/web/ui/prebuilt/Token/name.js +55 -26
  57. package/dist/esm/react/web/ui/prebuilt/Token/name.js.map +1 -1
  58. package/dist/esm/react/web/ui/prebuilt/Token/symbol.js +55 -26
  59. package/dist/esm/react/web/ui/prebuilt/Token/symbol.js.map +1 -1
  60. package/dist/esm/react/web/utils/storage.js +23 -0
  61. package/dist/esm/react/web/utils/storage.js.map +1 -0
  62. package/dist/esm/version.js +1 -1
  63. package/dist/types/exports/react.d.ts +1 -0
  64. package/dist/types/exports/react.d.ts.map +1 -1
  65. package/dist/types/extensions/prebuilts/deploy-published.d.ts.map +1 -1
  66. package/dist/types/extensions/prebuilts/process-ref-deployments.d.ts +17 -0
  67. package/dist/types/extensions/prebuilts/process-ref-deployments.d.ts.map +1 -0
  68. package/dist/types/extensions/thirdweb/write/publish.d.ts.map +1 -1
  69. package/dist/types/react/core/utils/storage.d.ts +1 -0
  70. package/dist/types/react/core/utils/storage.d.ts.map +1 -1
  71. package/dist/types/react/web/ui/prebuilt/Chain/icon.d.ts.map +1 -1
  72. package/dist/types/react/web/ui/prebuilt/Chain/name.d.ts +8 -0
  73. package/dist/types/react/web/ui/prebuilt/Chain/name.d.ts.map +1 -1
  74. package/dist/types/react/web/ui/prebuilt/NFT/description.d.ts.map +1 -1
  75. package/dist/types/react/web/ui/prebuilt/NFT/media.d.ts.map +1 -1
  76. package/dist/types/react/web/ui/prebuilt/NFT/name.d.ts.map +1 -1
  77. package/dist/types/react/web/ui/prebuilt/Token/icon.d.ts.map +1 -1
  78. package/dist/types/react/web/ui/prebuilt/Token/name.d.ts +21 -0
  79. package/dist/types/react/web/ui/prebuilt/Token/name.d.ts.map +1 -1
  80. package/dist/types/react/web/ui/prebuilt/Token/symbol.d.ts +21 -0
  81. package/dist/types/react/web/ui/prebuilt/Token/symbol.d.ts.map +1 -1
  82. package/dist/types/react/web/utils/storage.d.ts +19 -0
  83. package/dist/types/react/web/utils/storage.d.ts.map +1 -0
  84. package/dist/types/utils/any-evm/deploy-metadata.d.ts +19 -0
  85. package/dist/types/utils/any-evm/deploy-metadata.d.ts.map +1 -1
  86. package/dist/types/version.d.ts +1 -1
  87. package/package.json +8 -8
  88. package/src/contract/deployment/deploy-with-abi.ts +1 -1
  89. package/src/exports/react.ts +3 -0
  90. package/src/extensions/prebuilts/deploy-published.ts +36 -6
  91. package/src/extensions/prebuilts/process-ref-deployments.test.ts +196 -0
  92. package/src/extensions/prebuilts/process-ref-deployments.ts +167 -0
  93. package/src/extensions/thirdweb/write/publish.ts +1 -0
  94. package/src/react/core/utils/storage.ts +1 -1
  95. package/src/react/web/ui/prebuilt/Chain/icon.tsx +13 -1
  96. package/src/react/web/ui/prebuilt/Chain/name.test.tsx +36 -9
  97. package/src/react/web/ui/prebuilt/Chain/name.tsx +35 -13
  98. package/src/react/web/ui/prebuilt/NFT/description.tsx +2 -1
  99. package/src/react/web/ui/prebuilt/NFT/media.tsx +2 -1
  100. package/src/react/web/ui/prebuilt/NFT/name.tsx +2 -1
  101. package/src/react/web/ui/prebuilt/Token/icon.tsx +14 -1
  102. package/src/react/web/ui/prebuilt/Token/name.test.tsx +148 -0
  103. package/src/react/web/ui/prebuilt/Token/name.tsx +73 -29
  104. package/src/react/web/ui/prebuilt/Token/provider.test.tsx +11 -0
  105. package/src/react/web/ui/prebuilt/Token/symbol.test.tsx +138 -20
  106. package/src/react/web/ui/prebuilt/Token/symbol.tsx +73 -32
  107. package/src/react/web/utils/storage.test.ts +34 -0
  108. package/src/react/web/utils/storage.ts +23 -0
  109. package/src/utils/any-evm/deploy-metadata.ts +29 -0
  110. package/src/version.ts +1 -1
@@ -3,11 +3,14 @@
3
3
  import { type UseQueryOptions, useQuery } from "@tanstack/react-query";
4
4
  import type React from "react";
5
5
  import type { JSX } from "react";
6
+ import type { Chain } from "../../../../../chains/types.js";
6
7
  import { getChainMetadata } from "../../../../../chains/utils.js";
8
+ import type { ThirdwebClient } from "../../../../../client/client.js";
7
9
  import { NATIVE_TOKEN_ADDRESS } from "../../../../../constants/addresses.js";
8
10
  import { getContract } from "../../../../../contract/contract.js";
9
11
  import { getContractMetadata } from "../../../../../extensions/common/read/getContractMetadata.js";
10
12
  import { name } from "../../../../../extensions/common/read/name.js";
13
+ import { getFunctionId } from "../../../../../utils/function-id.js";
11
14
  import { useTokenContext } from "./provider.js";
12
15
 
13
16
  /**
@@ -157,33 +160,9 @@ export function TokenName({
157
160
  }: TokenNameProps) {
158
161
  const { address, client, chain } = useTokenContext();
159
162
  const nameQuery = useQuery({
160
- queryKey: ["_internal_token_name_", chain.id, address] as const,
161
- queryFn: async () => {
162
- if (typeof nameResolver === "string") {
163
- return nameResolver;
164
- }
165
- if (typeof nameResolver === "function") {
166
- return nameResolver();
167
- }
168
- if (address.toLowerCase() === NATIVE_TOKEN_ADDRESS.toLowerCase()) {
169
- // Don't wanna use `getChainNativeCurrencyName` because it has some side effect (it catches error and defaults to "ETH")
170
- return getChainMetadata(chain).then((data) => data.nativeCurrency.name);
171
- }
172
- // Try to fetch the name from both the `name()` function and the contract metadata
173
- // then prioritize the `name()`
174
- const contract = getContract({ address, client, chain });
175
- const [_name, contractMetadata] = await Promise.all([
176
- name({ contract }),
177
- getContractMetadata({ contract }),
178
- ]);
179
- if (!_name && !contractMetadata.name) {
180
- throw new Error(
181
- "Failed to resolve name from both name() and contract metadata",
182
- );
183
- }
184
-
185
- return _name || contractMetadata.name;
186
- },
163
+ queryKey: getQueryKeys({ chainId: chain.id, nameResolver, address }),
164
+ queryFn: async () =>
165
+ fetchTokenName({ address, chain, client, nameResolver }),
187
166
  ...queryOptions,
188
167
  });
189
168
 
@@ -195,7 +174,72 @@ export function TokenName({
195
174
  return fallbackComponent || null;
196
175
  }
197
176
 
198
- const displayValue = formatFn ? formatFn(nameQuery.data) : nameQuery.data;
177
+ if (formatFn && typeof formatFn === "function") {
178
+ return <span {...restProps}>{formatFn(nameQuery.data)}</span>;
179
+ }
180
+
181
+ return <span {...restProps}>{nameQuery.data}</span>;
182
+ }
183
+
184
+ /**
185
+ * @internal Exported for tests only
186
+ */
187
+ export async function fetchTokenName(props: {
188
+ address: string;
189
+ client: ThirdwebClient;
190
+ chain: Chain;
191
+ nameResolver?: string | (() => string) | (() => Promise<string>);
192
+ }) {
193
+ const { nameResolver, address, client, chain } = props;
194
+ if (typeof nameResolver === "string") {
195
+ return nameResolver;
196
+ }
197
+ if (typeof nameResolver === "function") {
198
+ return nameResolver();
199
+ }
200
+ if (address.toLowerCase() === NATIVE_TOKEN_ADDRESS.toLowerCase()) {
201
+ // Don't wanna use `getChainName` because it has some side effect (it catches error and defaults to "ETH")
202
+ return getChainMetadata(chain).then((data) => data.nativeCurrency.name);
203
+ }
204
+
205
+ // Try to fetch the name from both the `name` function and the contract metadata
206
+ // then prioritize its result
207
+ const contract = getContract({ address, client, chain });
208
+ const [_name, contractMetadata] = await Promise.all([
209
+ name({ contract }).catch(() => undefined),
210
+ getContractMetadata({ contract }).catch(() => undefined),
211
+ ]);
212
+ if (typeof _name === "string") {
213
+ return _name;
214
+ }
215
+ if (typeof contractMetadata?.name === "string") {
216
+ return contractMetadata.name;
217
+ }
218
+ throw new Error(
219
+ "Failed to resolve name from both name() and contract metadata",
220
+ );
221
+ }
199
222
 
200
- return <span {...restProps}>{displayValue}</span>;
223
+ /**
224
+ * @internal
225
+ */
226
+ export function getQueryKeys(props: {
227
+ chainId: number;
228
+ address: string;
229
+ nameResolver?: string | (() => string) | (() => Promise<string>);
230
+ }) {
231
+ const { chainId, address, nameResolver } = props;
232
+ return [
233
+ "_internal_token_name_",
234
+ chainId,
235
+ address,
236
+ {
237
+ resolver:
238
+ typeof nameResolver === "string"
239
+ ? nameResolver
240
+ : typeof nameResolver === "function"
241
+ ? getFunctionId(nameResolver)
242
+ : undefined,
243
+ },
244
+ ] as const;
201
245
  }
@@ -5,6 +5,7 @@ import { ethereum } from "../../../../../chains/chain-definitions/ethereum.js";
5
5
  import { NATIVE_TOKEN_ADDRESS } from "../../../../../constants/addresses.js";
6
6
  import { TokenName } from "./name.js";
7
7
  import { TokenProvider } from "./provider.js";
8
+ import { TokenSymbol } from "./symbol.js";
8
9
 
9
10
  describe.runIf(process.env.TW_SECRET_KEY)("TokenProvider component", () => {
10
11
  it("should render children correctly", () => {
@@ -29,6 +30,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("TokenProvider component", () => {
29
30
  chain={ethereum}
30
31
  >
31
32
  <TokenName />
33
+ <TokenSymbol />
32
34
  </TokenProvider>,
33
35
  );
34
36
 
@@ -40,5 +42,14 @@ describe.runIf(process.env.TW_SECRET_KEY)("TokenProvider component", () => {
40
42
  }),
41
43
  ).toBeInTheDocument(),
42
44
  );
45
+
46
+ waitFor(() =>
47
+ expect(
48
+ screen.getByText("ETH", {
49
+ exact: true,
50
+ selector: "span",
51
+ }),
52
+ ).toBeInTheDocument(),
53
+ );
43
54
  });
44
55
  });
@@ -1,30 +1,148 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { render, screen, waitFor } from "~test/react-render.js";
2
+ import { ANVIL_CHAIN } from "~test/chains.js";
3
+ import {} from "~test/react-render.js";
3
4
  import { TEST_CLIENT } from "~test/test-clients.js";
5
+ import {
6
+ UNISWAPV3_FACTORY_CONTRACT,
7
+ USDT_CONTRACT,
8
+ } from "~test/test-contracts.js";
4
9
  import { ethereum } from "../../../../../chains/chain-definitions/ethereum.js";
5
10
  import { NATIVE_TOKEN_ADDRESS } from "../../../../../constants/addresses.js";
6
- import { TokenProvider } from "./provider.js";
7
- import { TokenSymbol } from "./symbol.js";
11
+ import { getFunctionId } from "../../../../../utils/function-id.js";
12
+ import { fetchTokenSymbol, getQueryKeys } from "./symbol.js";
13
+
14
+ const client = TEST_CLIENT;
8
15
 
9
16
  describe.runIf(process.env.TW_SECRET_KEY)("TokenSymbol component", () => {
10
- it("should pass the address correctly to the children props", () => {
11
- render(
12
- <TokenProvider
13
- address={NATIVE_TOKEN_ADDRESS}
14
- client={TEST_CLIENT}
15
- chain={ethereum}
16
- >
17
- <TokenSymbol />
18
- </TokenProvider>,
19
- );
17
+ it("fetchTokenSymbol should respect the symbolResolver being a string", async () => {
18
+ const res = await fetchTokenSymbol({
19
+ address: "thing",
20
+ client,
21
+ chain: ANVIL_CHAIN,
22
+ symbolResolver: "tw",
23
+ });
24
+ expect(res).toBe("tw");
25
+ });
26
+
27
+ it("fetchTokenSymbol should respect the symbolResolver being a non-async function", async () => {
28
+ const res = await fetchTokenSymbol({
29
+ address: "thing",
30
+ client,
31
+ chain: ANVIL_CHAIN,
32
+ symbolResolver: () => "tw",
33
+ });
34
+
35
+ expect(res).toBe("tw");
36
+ });
37
+
38
+ it("fetchTokenSymbol should respect the symbolResolver being an async function", async () => {
39
+ const res = await fetchTokenSymbol({
40
+ address: "thing",
41
+ client,
42
+ chain: ANVIL_CHAIN,
43
+ symbolResolver: async () => {
44
+ await new Promise((resolve) => setTimeout(resolve, 2000));
45
+ return "tw";
46
+ },
47
+ });
48
+
49
+ expect(res).toBe("tw");
50
+ });
51
+
52
+ it("fetchTokenSymbol should work for contract with `symbol` function", async () => {
53
+ const res = await fetchTokenSymbol({
54
+ address: USDT_CONTRACT.address,
55
+ client,
56
+ chain: USDT_CONTRACT.chain,
57
+ });
58
+
59
+ expect(res).toBe("USDT");
60
+ });
61
+
62
+ it("fetchTokenSymbol should work for native token", async () => {
63
+ const res = await fetchTokenSymbol({
64
+ address: NATIVE_TOKEN_ADDRESS,
65
+ client,
66
+ chain: ethereum,
67
+ });
20
68
 
21
- waitFor(() =>
22
- expect(
23
- screen.getByText("ETH", {
24
- exact: true,
25
- selector: "span",
26
- }),
27
- ).toBeInTheDocument(),
69
+ expect(res).toBe("ETH");
70
+ });
71
+
72
+ it("fetchTokenSymbol should try to fallback to the contract metadata if fails to resolves from `symbol()`", async () => {
73
+ // todo: find a contract with symbol in contractMetadata, but does not have a symbol function
74
+ });
75
+
76
+ it("fetchTokenSymbol should throw in the end where all fallback solutions failed to resolve to any symbol", async () => {
77
+ await expect(() =>
78
+ fetchTokenSymbol({
79
+ address: UNISWAPV3_FACTORY_CONTRACT.address,
80
+ client,
81
+ chain: UNISWAPV3_FACTORY_CONTRACT.chain,
82
+ }),
83
+ ).rejects.toThrowError(
84
+ "Failed to resolve symbol from both symbol() and contract metadata",
28
85
  );
29
86
  });
87
+
88
+ it("getQueryKeys should work without resolver", () => {
89
+ expect(getQueryKeys({ chainId: 1, address: "0x" })).toStrictEqual([
90
+ "_internal_token_symbol_",
91
+ 1,
92
+ "0x",
93
+ {
94
+ resolver: undefined,
95
+ },
96
+ ]);
97
+ });
98
+
99
+ it("getQueryKeys should work with resolver being a string", () => {
100
+ expect(
101
+ getQueryKeys({ chainId: 1, address: "0x", symbolResolver: "tw" }),
102
+ ).toStrictEqual([
103
+ "_internal_token_symbol_",
104
+ 1,
105
+ "0x",
106
+ {
107
+ resolver: "tw",
108
+ },
109
+ ]);
110
+ });
111
+
112
+ it("getQueryKeys should work with resolver being a non-async fn that returns a string", () => {
113
+ const fn = () => "tw";
114
+ const fnId = getFunctionId(fn);
115
+ expect(
116
+ getQueryKeys({ chainId: 1, address: "0x", symbolResolver: fn }),
117
+ ).toStrictEqual([
118
+ "_internal_token_symbol_",
119
+ 1,
120
+ "0x",
121
+ {
122
+ resolver: fnId,
123
+ },
124
+ ]);
125
+ });
126
+
127
+ it("getQueryKeys should work with resolver being an async fn that returns a string", () => {
128
+ const fn = async () => {
129
+ await new Promise((resolve) => setTimeout(resolve, 2000));
130
+ return "tw";
131
+ };
132
+ const fnId = getFunctionId(fn);
133
+ expect(
134
+ getQueryKeys({
135
+ chainId: 1,
136
+ address: "0x",
137
+ symbolResolver: fn,
138
+ }),
139
+ ).toStrictEqual([
140
+ "_internal_token_symbol_",
141
+ 1,
142
+ "0x",
143
+ {
144
+ resolver: fnId,
145
+ },
146
+ ]);
147
+ });
30
148
  });
@@ -3,11 +3,14 @@
3
3
  import { type UseQueryOptions, useQuery } from "@tanstack/react-query";
4
4
  import type React from "react";
5
5
  import type { JSX } from "react";
6
+ import type { Chain } from "../../../../../chains/types.js";
6
7
  import { getChainMetadata } from "../../../../../chains/utils.js";
8
+ import type { ThirdwebClient } from "../../../../../client/client.js";
7
9
  import { NATIVE_TOKEN_ADDRESS } from "../../../../../constants/addresses.js";
8
10
  import { getContract } from "../../../../../contract/contract.js";
9
11
  import { getContractMetadata } from "../../../../../extensions/common/read/getContractMetadata.js";
10
12
  import { symbol } from "../../../../../extensions/common/read/symbol.js";
13
+ import { getFunctionId } from "../../../../../utils/function-id.js";
11
14
  import { useTokenContext } from "./provider.js";
12
15
 
13
16
  /**
@@ -154,36 +157,9 @@ export function TokenSymbol({
154
157
  }: TokenSymbolProps) {
155
158
  const { address, client, chain } = useTokenContext();
156
159
  const symbolQuery = useQuery({
157
- queryKey: ["_internal_token_symbol_", chain.id, address] as const,
158
- queryFn: async () => {
159
- if (typeof symbolResolver === "string") {
160
- return symbolResolver;
161
- }
162
- if (typeof symbolResolver === "function") {
163
- return symbolResolver();
164
- }
165
- if (address.toLowerCase() === NATIVE_TOKEN_ADDRESS.toLowerCase()) {
166
- // Don't wanna use `getChainSymbol` because it has some side effect (it catches error and defaults to "ETH")
167
- return getChainMetadata(chain).then(
168
- (data) => data.nativeCurrency.symbol,
169
- );
170
- }
171
-
172
- // Try to fetch the symbol from both the `symbol` function and the contract metadata
173
- // then prioritize the `symbol()`
174
- const contract = getContract({ address, client, chain });
175
- const [_symbol, contractMetadata] = await Promise.all([
176
- symbol({ contract }),
177
- getContractMetadata({ contract }),
178
- ]);
179
- if (!_symbol && !contractMetadata.symbol) {
180
- throw new Error(
181
- "Failed to resolve symbol from both symbol() and contract metadata",
182
- );
183
- }
184
-
185
- return _symbol || contractMetadata.symbol;
186
- },
160
+ queryKey: getQueryKeys({ chainId: chain.id, address, symbolResolver }),
161
+ queryFn: async () =>
162
+ fetchTokenSymbol({ symbolResolver, address, chain, client }),
187
163
  ...queryOptions,
188
164
  });
189
165
 
@@ -195,7 +171,72 @@ export function TokenSymbol({
195
171
  return fallbackComponent || null;
196
172
  }
197
173
 
198
- const displayValue = formatFn ? formatFn(symbolQuery.data) : symbolQuery.data;
174
+ if (formatFn && typeof formatFn === "function") {
175
+ return <span {...restProps}>{formatFn(symbolQuery.data)}</span>;
176
+ }
177
+
178
+ return <span {...restProps}>{symbolQuery.data}</span>;
179
+ }
199
180
 
200
- return <span {...restProps}>{displayValue}</span>;
181
+ /**
182
+ * @internal Exported for tests only
183
+ */
184
+ export async function fetchTokenSymbol(props: {
185
+ address: string;
186
+ client: ThirdwebClient;
187
+ chain: Chain;
188
+ symbolResolver?: string | (() => string) | (() => Promise<string>);
189
+ }): Promise<string> {
190
+ const { symbolResolver, address, client, chain } = props;
191
+ if (typeof symbolResolver === "string") {
192
+ return symbolResolver;
193
+ }
194
+ if (typeof symbolResolver === "function") {
195
+ return symbolResolver();
196
+ }
197
+ if (address.toLowerCase() === NATIVE_TOKEN_ADDRESS.toLowerCase()) {
198
+ // Don't wanna use `getChainSymbol` because it has some side effect (it catches error and defaults to "ETH")
199
+ return getChainMetadata(chain).then((data) => data.nativeCurrency.symbol);
200
+ }
201
+
202
+ // Try to fetch the symbol from both the `symbol` function and the contract metadata
203
+ // then prioritize its result
204
+ const contract = getContract({ address, client, chain });
205
+ const [_symbol, contractMetadata] = await Promise.all([
206
+ symbol({ contract }).catch(() => undefined),
207
+ getContractMetadata({ contract }).catch(() => undefined),
208
+ ]);
209
+ if (typeof _symbol === "string") {
210
+ return _symbol;
211
+ }
212
+ if (typeof contractMetadata?.symbol === "string") {
213
+ return contractMetadata.symbol;
214
+ }
215
+ throw new Error(
216
+ "Failed to resolve symbol from both symbol() and contract metadata",
217
+ );
218
+ }
219
+
220
+ /**
221
+ * @internal
222
+ */
223
+ export function getQueryKeys(props: {
224
+ chainId: number;
225
+ address: string;
226
+ symbolResolver?: string | (() => string) | (() => Promise<string>);
227
+ }) {
228
+ const { chainId, address, symbolResolver } = props;
229
+ return [
230
+ "_internal_token_symbol_",
231
+ chainId,
232
+ address,
233
+ {
234
+ resolver:
235
+ typeof symbolResolver === "string"
236
+ ? symbolResolver
237
+ : typeof symbolResolver === "function"
238
+ ? getFunctionId(symbolResolver)
239
+ : undefined,
240
+ },
241
+ ] as const;
201
242
  }
@@ -0,0 +1,34 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { webLocalStorage } from "../../../utils/storage/webStorage.js";
3
+ import { LAST_AUTH_PROVIDER_STORAGE_KEY } from "../../core/utils/storage.js";
4
+ import { getLastAuthProvider } from "./storage.js";
5
+
6
+ vi.mock("../../../utils/storage/webStorage.js", () => ({
7
+ webLocalStorage: {
8
+ getItem: vi.fn().mockResolvedValueOnce("mockStrategy"),
9
+ },
10
+ }));
11
+
12
+ describe("getLastAuthProvider", () => {
13
+ it("should return the last authentication provider strategy if it exists", async () => {
14
+ const mockStrategy = "mockStrategy";
15
+ webLocalStorage.getItem = vi.fn().mockResolvedValueOnce(mockStrategy);
16
+
17
+ const result = await getLastAuthProvider();
18
+ expect(result).toBe(mockStrategy);
19
+ });
20
+
21
+ it("should return null if no authentication provider strategy is found", async () => {
22
+ webLocalStorage.getItem = vi.fn().mockResolvedValueOnce(null);
23
+
24
+ const result = await getLastAuthProvider();
25
+ expect(result).toBeNull();
26
+ });
27
+
28
+ it("should call webLocalStorage.getItem with the correct key", async () => {
29
+ await getLastAuthProvider();
30
+ expect(webLocalStorage.getItem).toHaveBeenCalledWith(
31
+ LAST_AUTH_PROVIDER_STORAGE_KEY,
32
+ );
33
+ });
34
+ });
@@ -0,0 +1,23 @@
1
+ import { webLocalStorage } from "../../../utils/storage/webStorage.js";
2
+ import { getLastAuthProvider as getLastAuthProviderCore } from "../../core/utils/storage.js";
3
+
4
+ /**
5
+ * Retrieves the last authentication provider used from local storage.
6
+ *
7
+ * This function is designed to work only in a browser environment.
8
+ *
9
+ * @returns {Promise<AuthArgsType["strategy"] | null>} A promise that resolves to the last
10
+ * authentication provider strategy used, or `null` if none is found.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import { getLastAuthProvider } from "thirdweb/react";
15
+ *
16
+ * const lastAuthProvider = await getLastAuthProvider();
17
+ * ```
18
+ *
19
+ * @utils
20
+ */
21
+ export async function getLastAuthProvider() {
22
+ return getLastAuthProviderCore(webLocalStorage);
23
+ }
@@ -159,6 +159,27 @@ type ParsedCompilerMetadata = {
159
159
  zk_version?: string;
160
160
  };
161
161
 
162
+ export type DynamicParams = {
163
+ type: "address" | "address[]" | "bytes" | "bytes[]";
164
+
165
+ // use for address types
166
+ refContracts?: Array<{
167
+ contractId: string;
168
+ publisherAddress: string;
169
+ version: string;
170
+ salt?: string;
171
+ }>;
172
+
173
+ // use for bytes
174
+ paramsToEncode?: Array<
175
+ Array<{
176
+ type: string;
177
+ defaultValue?: string;
178
+ dynamicValue?: DynamicParams; // can have address type which may need ref
179
+ }>
180
+ >;
181
+ };
182
+
162
183
  export type CompilerMetadata = Prettify<
163
184
  RawCompilerMetadata & ParsedCompilerMetadata
164
185
  >;
@@ -220,6 +241,14 @@ export type ExtendedMetadata = {
220
241
  description?: string;
221
242
  defaultValue?: string;
222
243
  hidden?: boolean;
244
+ dynamicValue?: DynamicParams;
245
+ }
246
+ >;
247
+ implConstructorParams?: Record<
248
+ string,
249
+ {
250
+ defaultValue?: string;
251
+ dynamicValue?: DynamicParams;
223
252
  }
224
253
  >;
225
254
  compositeAbi?: Abi;
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = "5.76.1";
1
+ export const version = "5.77.0";