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.
- package/dist/cjs/contract/deployment/deploy-with-abi.js +1 -1
- package/dist/cjs/contract/deployment/deploy-with-abi.js.map +1 -1
- package/dist/cjs/exports/react.js +4 -1
- package/dist/cjs/exports/react.js.map +1 -1
- package/dist/cjs/extensions/prebuilts/deploy-published.js +25 -6
- package/dist/cjs/extensions/prebuilts/deploy-published.js.map +1 -1
- package/dist/cjs/extensions/prebuilts/process-ref-deployments.js +117 -0
- package/dist/cjs/extensions/prebuilts/process-ref-deployments.js.map +1 -0
- package/dist/cjs/extensions/thirdweb/write/publish.js +1 -0
- package/dist/cjs/extensions/thirdweb/write/publish.js.map +1 -1
- package/dist/cjs/react/core/utils/storage.js +4 -3
- package/dist/cjs/react/core/utils/storage.js.map +1 -1
- package/dist/cjs/react/web/ui/prebuilt/Chain/icon.js +12 -1
- package/dist/cjs/react/web/ui/prebuilt/Chain/icon.js.map +1 -1
- package/dist/cjs/react/web/ui/prebuilt/Chain/name.js +30 -13
- package/dist/cjs/react/web/ui/prebuilt/Chain/name.js.map +1 -1
- package/dist/cjs/react/web/ui/prebuilt/NFT/description.js +2 -1
- package/dist/cjs/react/web/ui/prebuilt/NFT/description.js.map +1 -1
- package/dist/cjs/react/web/ui/prebuilt/NFT/media.js +2 -1
- package/dist/cjs/react/web/ui/prebuilt/NFT/media.js.map +1 -1
- package/dist/cjs/react/web/ui/prebuilt/NFT/name.js +2 -1
- package/dist/cjs/react/web/ui/prebuilt/NFT/name.js.map +1 -1
- package/dist/cjs/react/web/ui/prebuilt/Token/icon.js +13 -1
- package/dist/cjs/react/web/ui/prebuilt/Token/icon.js.map +1 -1
- package/dist/cjs/react/web/ui/prebuilt/Token/name.js +57 -26
- package/dist/cjs/react/web/ui/prebuilt/Token/name.js.map +1 -1
- package/dist/cjs/react/web/ui/prebuilt/Token/symbol.js +57 -26
- package/dist/cjs/react/web/ui/prebuilt/Token/symbol.js.map +1 -1
- package/dist/cjs/react/web/utils/storage.js +26 -0
- package/dist/cjs/react/web/utils/storage.js.map +1 -0
- package/dist/cjs/version.js +1 -1
- package/dist/esm/contract/deployment/deploy-with-abi.js +1 -1
- package/dist/esm/contract/deployment/deploy-with-abi.js.map +1 -1
- package/dist/esm/exports/react.js +2 -0
- package/dist/esm/exports/react.js.map +1 -1
- package/dist/esm/extensions/prebuilts/deploy-published.js +25 -6
- package/dist/esm/extensions/prebuilts/deploy-published.js.map +1 -1
- package/dist/esm/extensions/prebuilts/process-ref-deployments.js +114 -0
- package/dist/esm/extensions/prebuilts/process-ref-deployments.js.map +1 -0
- package/dist/esm/extensions/thirdweb/write/publish.js +1 -0
- package/dist/esm/extensions/thirdweb/write/publish.js.map +1 -1
- package/dist/esm/react/core/utils/storage.js +1 -1
- package/dist/esm/react/core/utils/storage.js.map +1 -1
- package/dist/esm/react/web/ui/prebuilt/Chain/icon.js +12 -1
- package/dist/esm/react/web/ui/prebuilt/Chain/icon.js.map +1 -1
- package/dist/esm/react/web/ui/prebuilt/Chain/name.js +29 -13
- package/dist/esm/react/web/ui/prebuilt/Chain/name.js.map +1 -1
- package/dist/esm/react/web/ui/prebuilt/NFT/description.js +2 -1
- package/dist/esm/react/web/ui/prebuilt/NFT/description.js.map +1 -1
- package/dist/esm/react/web/ui/prebuilt/NFT/media.js +2 -1
- package/dist/esm/react/web/ui/prebuilt/NFT/media.js.map +1 -1
- package/dist/esm/react/web/ui/prebuilt/NFT/name.js +2 -1
- package/dist/esm/react/web/ui/prebuilt/NFT/name.js.map +1 -1
- package/dist/esm/react/web/ui/prebuilt/Token/icon.js +13 -1
- package/dist/esm/react/web/ui/prebuilt/Token/icon.js.map +1 -1
- package/dist/esm/react/web/ui/prebuilt/Token/name.js +55 -26
- package/dist/esm/react/web/ui/prebuilt/Token/name.js.map +1 -1
- package/dist/esm/react/web/ui/prebuilt/Token/symbol.js +55 -26
- package/dist/esm/react/web/ui/prebuilt/Token/symbol.js.map +1 -1
- package/dist/esm/react/web/utils/storage.js +23 -0
- package/dist/esm/react/web/utils/storage.js.map +1 -0
- package/dist/esm/version.js +1 -1
- package/dist/types/exports/react.d.ts +1 -0
- package/dist/types/exports/react.d.ts.map +1 -1
- package/dist/types/extensions/prebuilts/deploy-published.d.ts.map +1 -1
- package/dist/types/extensions/prebuilts/process-ref-deployments.d.ts +17 -0
- package/dist/types/extensions/prebuilts/process-ref-deployments.d.ts.map +1 -0
- package/dist/types/extensions/thirdweb/write/publish.d.ts.map +1 -1
- package/dist/types/react/core/utils/storage.d.ts +1 -0
- package/dist/types/react/core/utils/storage.d.ts.map +1 -1
- package/dist/types/react/web/ui/prebuilt/Chain/icon.d.ts.map +1 -1
- package/dist/types/react/web/ui/prebuilt/Chain/name.d.ts +8 -0
- package/dist/types/react/web/ui/prebuilt/Chain/name.d.ts.map +1 -1
- package/dist/types/react/web/ui/prebuilt/NFT/description.d.ts.map +1 -1
- package/dist/types/react/web/ui/prebuilt/NFT/media.d.ts.map +1 -1
- package/dist/types/react/web/ui/prebuilt/NFT/name.d.ts.map +1 -1
- package/dist/types/react/web/ui/prebuilt/Token/icon.d.ts.map +1 -1
- package/dist/types/react/web/ui/prebuilt/Token/name.d.ts +21 -0
- package/dist/types/react/web/ui/prebuilt/Token/name.d.ts.map +1 -1
- package/dist/types/react/web/ui/prebuilt/Token/symbol.d.ts +21 -0
- package/dist/types/react/web/ui/prebuilt/Token/symbol.d.ts.map +1 -1
- package/dist/types/react/web/utils/storage.d.ts +19 -0
- package/dist/types/react/web/utils/storage.d.ts.map +1 -0
- package/dist/types/utils/any-evm/deploy-metadata.d.ts +19 -0
- package/dist/types/utils/any-evm/deploy-metadata.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/package.json +8 -8
- package/src/contract/deployment/deploy-with-abi.ts +1 -1
- package/src/exports/react.ts +3 -0
- package/src/extensions/prebuilts/deploy-published.ts +36 -6
- package/src/extensions/prebuilts/process-ref-deployments.test.ts +196 -0
- package/src/extensions/prebuilts/process-ref-deployments.ts +167 -0
- package/src/extensions/thirdweb/write/publish.ts +1 -0
- package/src/react/core/utils/storage.ts +1 -1
- package/src/react/web/ui/prebuilt/Chain/icon.tsx +13 -1
- package/src/react/web/ui/prebuilt/Chain/name.test.tsx +36 -9
- package/src/react/web/ui/prebuilt/Chain/name.tsx +35 -13
- package/src/react/web/ui/prebuilt/NFT/description.tsx +2 -1
- package/src/react/web/ui/prebuilt/NFT/media.tsx +2 -1
- package/src/react/web/ui/prebuilt/NFT/name.tsx +2 -1
- package/src/react/web/ui/prebuilt/Token/icon.tsx +14 -1
- package/src/react/web/ui/prebuilt/Token/name.test.tsx +148 -0
- package/src/react/web/ui/prebuilt/Token/name.tsx +73 -29
- package/src/react/web/ui/prebuilt/Token/provider.test.tsx +11 -0
- package/src/react/web/ui/prebuilt/Token/symbol.test.tsx +138 -20
- package/src/react/web/ui/prebuilt/Token/symbol.tsx +73 -32
- package/src/react/web/utils/storage.test.ts +34 -0
- package/src/react/web/utils/storage.ts +23 -0
- package/src/utils/any-evm/deploy-metadata.ts +29 -0
- 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:
|
161
|
-
queryFn: async () =>
|
162
|
-
|
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
|
-
|
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
|
-
|
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 {
|
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 {
|
7
|
-
import {
|
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
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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:
|
158
|
-
queryFn: async () =>
|
159
|
-
|
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
|
-
|
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
|
-
|
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.
|
1
|
+
export const version = "5.77.0";
|