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
@@ -0,0 +1,167 @@
|
|
1
|
+
import type { Chain } from "../../chains/types.js";
|
2
|
+
import type { ThirdwebClient } from "../../client/client.js";
|
3
|
+
import { encodeAbiParameters } from "../../utils/abi/encodeAbiParameters.js";
|
4
|
+
import type { DynamicParams } from "../../utils/any-evm/deploy-metadata.js";
|
5
|
+
import type { Account } from "../../wallets/interfaces/wallet.js";
|
6
|
+
import { deployPublishedContract } from "./deploy-published.js";
|
7
|
+
|
8
|
+
export type ImplementationConstructorParam = {
|
9
|
+
defaultValue?: string;
|
10
|
+
dynamicValue?: DynamicParams;
|
11
|
+
};
|
12
|
+
|
13
|
+
type ProcessRefDeploymentsOptions = {
|
14
|
+
client: ThirdwebClient;
|
15
|
+
chain: Chain;
|
16
|
+
account: Account;
|
17
|
+
paramValue: string | ImplementationConstructorParam;
|
18
|
+
};
|
19
|
+
|
20
|
+
export async function processRefDeployments(
|
21
|
+
options: ProcessRefDeploymentsOptions,
|
22
|
+
): Promise<string | string[]> {
|
23
|
+
const { client, account, chain, paramValue } = options;
|
24
|
+
|
25
|
+
if (typeof paramValue === "object") {
|
26
|
+
if (
|
27
|
+
"defaultValue" in paramValue &&
|
28
|
+
paramValue.defaultValue &&
|
29
|
+
paramValue.defaultValue.length > 0
|
30
|
+
) {
|
31
|
+
return paramValue.defaultValue;
|
32
|
+
}
|
33
|
+
|
34
|
+
if ("dynamicValue" in paramValue && paramValue.dynamicValue) {
|
35
|
+
const dynamicValue = paramValue.dynamicValue;
|
36
|
+
const contracts = dynamicValue.refContracts;
|
37
|
+
|
38
|
+
if (dynamicValue.type === "address") {
|
39
|
+
if (!contracts || contracts.length === 0 || !contracts[0]?.contractId) {
|
40
|
+
throw new Error("Invalid or empty param value");
|
41
|
+
}
|
42
|
+
const salt =
|
43
|
+
contracts[0]?.salt && contracts[0]?.salt.length > 0
|
44
|
+
? contracts[0]?.salt
|
45
|
+
: "thirdweb";
|
46
|
+
|
47
|
+
const addr = await deployPublishedContract({
|
48
|
+
client,
|
49
|
+
chain,
|
50
|
+
account,
|
51
|
+
contractId: contracts[0]?.contractId,
|
52
|
+
publisher: contracts[0]?.publisherAddress,
|
53
|
+
version: contracts[0]?.version,
|
54
|
+
salt,
|
55
|
+
});
|
56
|
+
|
57
|
+
return addr;
|
58
|
+
}
|
59
|
+
|
60
|
+
if (dynamicValue.type === "address[]") {
|
61
|
+
if (!contracts || contracts.length === 0) {
|
62
|
+
throw new Error("Invalid or empty param value");
|
63
|
+
}
|
64
|
+
const addressArray = [];
|
65
|
+
|
66
|
+
for (const c of contracts) {
|
67
|
+
const salt = c?.salt && c?.salt.length > 0 ? c?.salt : "thirdweb";
|
68
|
+
|
69
|
+
addressArray.push(
|
70
|
+
await deployPublishedContract({
|
71
|
+
client,
|
72
|
+
chain,
|
73
|
+
account,
|
74
|
+
contractId: c.contractId,
|
75
|
+
publisher: c.publisherAddress,
|
76
|
+
version: c.version,
|
77
|
+
salt,
|
78
|
+
}),
|
79
|
+
);
|
80
|
+
}
|
81
|
+
|
82
|
+
return addressArray;
|
83
|
+
}
|
84
|
+
|
85
|
+
if (dynamicValue.type === "bytes") {
|
86
|
+
if (!dynamicValue.paramsToEncode) {
|
87
|
+
throw new Error("Invalid or empty param value");
|
88
|
+
}
|
89
|
+
const paramsToEncode = dynamicValue.paramsToEncode[0];
|
90
|
+
|
91
|
+
if (paramsToEncode) {
|
92
|
+
const types = [];
|
93
|
+
const values = [];
|
94
|
+
for (const v of paramsToEncode) {
|
95
|
+
types.push(v.type);
|
96
|
+
|
97
|
+
if (v.defaultValue) {
|
98
|
+
values.push(v.defaultValue);
|
99
|
+
} else if (v.dynamicValue) {
|
100
|
+
values.push(
|
101
|
+
await processRefDeployments({
|
102
|
+
client,
|
103
|
+
account,
|
104
|
+
chain,
|
105
|
+
paramValue: v,
|
106
|
+
}),
|
107
|
+
);
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
return encodeAbiParameters(
|
112
|
+
types.map((t) => {
|
113
|
+
return { type: t };
|
114
|
+
}),
|
115
|
+
values,
|
116
|
+
);
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
if (dynamicValue.type === "bytes[]") {
|
121
|
+
if (!dynamicValue.paramsToEncode) {
|
122
|
+
throw new Error("Invalid or empty param value");
|
123
|
+
}
|
124
|
+
const bytesArray = [];
|
125
|
+
const paramArray = dynamicValue.paramsToEncode;
|
126
|
+
|
127
|
+
for (const a of paramArray) {
|
128
|
+
const paramsToEncode = a;
|
129
|
+
|
130
|
+
if (paramsToEncode) {
|
131
|
+
const types = [];
|
132
|
+
const values = [];
|
133
|
+
for (const v of paramsToEncode) {
|
134
|
+
types.push(v.type);
|
135
|
+
|
136
|
+
if (v.defaultValue) {
|
137
|
+
values.push(v.defaultValue);
|
138
|
+
} else if (v.dynamicValue) {
|
139
|
+
values.push(
|
140
|
+
await processRefDeployments({
|
141
|
+
client,
|
142
|
+
account,
|
143
|
+
chain,
|
144
|
+
paramValue: v,
|
145
|
+
}),
|
146
|
+
);
|
147
|
+
}
|
148
|
+
}
|
149
|
+
|
150
|
+
bytesArray.push(
|
151
|
+
encodeAbiParameters(
|
152
|
+
types.map((t) => {
|
153
|
+
return { type: t };
|
154
|
+
}),
|
155
|
+
values,
|
156
|
+
),
|
157
|
+
);
|
158
|
+
}
|
159
|
+
}
|
160
|
+
|
161
|
+
return bytesArray;
|
162
|
+
}
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
return paramValue as string;
|
167
|
+
}
|
@@ -78,6 +78,7 @@ export function publishContract(
|
|
78
78
|
changelog: options.metadata.changelog,
|
79
79
|
compositeAbi: options.metadata.compositeAbi,
|
80
80
|
constructorParams: options.metadata.constructorParams,
|
81
|
+
implConstructorParams: options.metadata.implConstructorParams,
|
81
82
|
defaultExtensions: options.metadata.defaultExtensions,
|
82
83
|
defaultModules: options.metadata.defaultModules,
|
83
84
|
deployType: options.metadata.deployType,
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import type { AsyncStorage } from "../../../utils/storage/AsyncStorage.js";
|
2
2
|
import type { AuthArgsType } from "../../../wallets/in-app/core/authentication/types.js";
|
3
3
|
|
4
|
-
const LAST_AUTH_PROVIDER_STORAGE_KEY = "lastAuthProvider";
|
4
|
+
export const LAST_AUTH_PROVIDER_STORAGE_KEY = "lastAuthProvider";
|
5
5
|
|
6
6
|
export async function setLastAuthProvider(
|
7
7
|
authProvider: AuthArgsType["strategy"],
|
@@ -4,6 +4,7 @@ import { type UseQueryOptions, useQuery } from "@tanstack/react-query";
|
|
4
4
|
import type { JSX } from "react";
|
5
5
|
import { getChainMetadata } from "../../../../../chains/utils.js";
|
6
6
|
import type { ThirdwebClient } from "../../../../../client/client.js";
|
7
|
+
import { getFunctionId } from "../../../../../utils/function-id.js";
|
7
8
|
import { resolveScheme } from "../../../../../utils/ipfs.js";
|
8
9
|
import { useChainContext } from "./provider.js";
|
9
10
|
|
@@ -121,7 +122,18 @@ export function ChainIcon({
|
|
121
122
|
}: ChainIconProps) {
|
122
123
|
const { chain } = useChainContext();
|
123
124
|
const iconQuery = useQuery({
|
124
|
-
queryKey: [
|
125
|
+
queryKey: [
|
126
|
+
"_internal_chain_icon_",
|
127
|
+
chain.id,
|
128
|
+
{
|
129
|
+
resolver:
|
130
|
+
typeof iconResolver === "string"
|
131
|
+
? iconResolver
|
132
|
+
: typeof iconResolver === "function"
|
133
|
+
? getFunctionId(iconResolver)
|
134
|
+
: undefined,
|
135
|
+
},
|
136
|
+
] as const,
|
125
137
|
queryFn: async () => {
|
126
138
|
if (typeof iconResolver === "string") {
|
127
139
|
return iconResolver;
|
@@ -2,17 +2,17 @@ import { describe, expect, it } from "vitest";
|
|
2
2
|
import { render, screen, waitFor } from "~test/react-render.js";
|
3
3
|
import { ethereum } from "../../../../../chains/chain-definitions/ethereum.js";
|
4
4
|
import { defineChain } from "../../../../../chains/utils.js";
|
5
|
-
import { ChainName } from "./name.js";
|
5
|
+
import { ChainName, fetchChainName } from "./name.js";
|
6
6
|
import { ChainProvider } from "./provider.js";
|
7
7
|
|
8
8
|
describe.runIf(process.env.TW_SECRET_KEY)("ChainName component", () => {
|
9
|
-
it("should return the correct chain name, if the name exists in the chain object", () => {
|
9
|
+
it("should return the correct chain name, if the name exists in the chain object", async () => {
|
10
10
|
render(
|
11
11
|
<ChainProvider chain={ethereum}>
|
12
12
|
<ChainName />
|
13
13
|
</ChainProvider>,
|
14
14
|
);
|
15
|
-
waitFor(() =>
|
15
|
+
await waitFor(() =>
|
16
16
|
expect(
|
17
17
|
screen.getByText("Ethereum", {
|
18
18
|
exact: true,
|
@@ -22,13 +22,13 @@ describe.runIf(process.env.TW_SECRET_KEY)("ChainName component", () => {
|
|
22
22
|
);
|
23
23
|
});
|
24
24
|
|
25
|
-
it("should return the correct chain name, if the name is loaded from the server", () => {
|
25
|
+
it("should return the correct chain name, if the name is loaded from the server", async () => {
|
26
26
|
render(
|
27
27
|
<ChainProvider chain={defineChain(1)}>
|
28
28
|
<ChainName />
|
29
29
|
</ChainProvider>,
|
30
30
|
);
|
31
|
-
waitFor(() =>
|
31
|
+
await waitFor(() =>
|
32
32
|
expect(
|
33
33
|
screen.getByText("Ethereum Mainnet", {
|
34
34
|
exact: true,
|
@@ -38,13 +38,13 @@ describe.runIf(process.env.TW_SECRET_KEY)("ChainName component", () => {
|
|
38
38
|
);
|
39
39
|
});
|
40
40
|
|
41
|
-
it("should return the correct FORMATTED chain name", () => {
|
41
|
+
it("should return the correct FORMATTED chain name", async () => {
|
42
42
|
render(
|
43
43
|
<ChainProvider chain={ethereum}>
|
44
44
|
<ChainName formatFn={(str: string) => `${str}-formatted`} />
|
45
45
|
</ChainProvider>,
|
46
46
|
);
|
47
|
-
waitFor(() =>
|
47
|
+
await waitFor(() =>
|
48
48
|
expect(
|
49
49
|
screen.getByText("Ethereum-formatted", {
|
50
50
|
exact: true,
|
@@ -54,14 +54,14 @@ describe.runIf(process.env.TW_SECRET_KEY)("ChainName component", () => {
|
|
54
54
|
);
|
55
55
|
});
|
56
56
|
|
57
|
-
it("should fallback properly when fail to resolve chain name", () => {
|
57
|
+
it("should fallback properly when fail to resolve chain name", async () => {
|
58
58
|
render(
|
59
59
|
<ChainProvider chain={defineChain(-1)}>
|
60
60
|
<ChainName fallbackComponent={<span>oops</span>} />
|
61
61
|
</ChainProvider>,
|
62
62
|
);
|
63
63
|
|
64
|
-
waitFor(() =>
|
64
|
+
await waitFor(() =>
|
65
65
|
expect(
|
66
66
|
screen.getByText("oops", {
|
67
67
|
exact: true,
|
@@ -70,4 +70,31 @@ describe.runIf(process.env.TW_SECRET_KEY)("ChainName component", () => {
|
|
70
70
|
).toBeInTheDocument(),
|
71
71
|
);
|
72
72
|
});
|
73
|
+
|
74
|
+
it("fetchChainName should respect nameResolver as a string", async () => {
|
75
|
+
const res = await fetchChainName({
|
76
|
+
chain: ethereum,
|
77
|
+
nameResolver: "eth_mainnet",
|
78
|
+
});
|
79
|
+
expect(res).toBe("eth_mainnet");
|
80
|
+
});
|
81
|
+
|
82
|
+
it("fetchChainName should respect nameResolver as a non-async function", async () => {
|
83
|
+
const res = await fetchChainName({
|
84
|
+
chain: ethereum,
|
85
|
+
nameResolver: () => "eth_mainnet",
|
86
|
+
});
|
87
|
+
expect(res).toBe("eth_mainnet");
|
88
|
+
});
|
89
|
+
|
90
|
+
it("fetchChainName should respect nameResolver as an async function", async () => {
|
91
|
+
const res = await fetchChainName({
|
92
|
+
chain: ethereum,
|
93
|
+
nameResolver: async () => {
|
94
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
95
|
+
return "eth_mainnet";
|
96
|
+
},
|
97
|
+
});
|
98
|
+
expect(res).toBe("eth_mainnet");
|
99
|
+
});
|
73
100
|
});
|
@@ -3,7 +3,9 @@
|
|
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 { getFunctionId } from "../../../../../utils/function-id.js";
|
7
9
|
import { useChainContext } from "./provider.js";
|
8
10
|
|
9
11
|
/**
|
@@ -155,19 +157,19 @@ export function ChainName({
|
|
155
157
|
}: ChainNameProps) {
|
156
158
|
const { chain } = useChainContext();
|
157
159
|
const nameQuery = useQuery({
|
158
|
-
queryKey: [
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
}
|
169
|
-
|
170
|
-
},
|
160
|
+
queryKey: [
|
161
|
+
"_internal_chain_name_",
|
162
|
+
chain.id,
|
163
|
+
{
|
164
|
+
resolver:
|
165
|
+
typeof nameResolver === "string"
|
166
|
+
? nameResolver
|
167
|
+
: typeof nameResolver === "function"
|
168
|
+
? getFunctionId(nameResolver)
|
169
|
+
: undefined,
|
170
|
+
},
|
171
|
+
] as const,
|
172
|
+
queryFn: async () => fetchChainName({ chain, nameResolver }),
|
171
173
|
...queryOptions,
|
172
174
|
});
|
173
175
|
|
@@ -183,3 +185,23 @@ export function ChainName({
|
|
183
185
|
|
184
186
|
return <span {...restProps}>{displayValue}</span>;
|
185
187
|
}
|
188
|
+
|
189
|
+
/**
|
190
|
+
* @internal Exported for tests only
|
191
|
+
*/
|
192
|
+
export async function fetchChainName(props: {
|
193
|
+
chain: Chain;
|
194
|
+
nameResolver?: string | (() => string) | (() => Promise<string>);
|
195
|
+
}) {
|
196
|
+
const { nameResolver, chain } = props;
|
197
|
+
if (typeof nameResolver === "string") {
|
198
|
+
return nameResolver;
|
199
|
+
}
|
200
|
+
if (typeof nameResolver === "function") {
|
201
|
+
return nameResolver();
|
202
|
+
}
|
203
|
+
if (chain.name) {
|
204
|
+
return chain.name;
|
205
|
+
}
|
206
|
+
return getChainMetadata(chain).then((data) => data.name);
|
207
|
+
}
|
@@ -3,6 +3,7 @@
|
|
3
3
|
import { type UseQueryOptions, useQuery } from "@tanstack/react-query";
|
4
4
|
import type { JSX } from "react";
|
5
5
|
import type { ThirdwebContract } from "../../../../../contract/contract.js";
|
6
|
+
import { getFunctionId } from "../../../../../utils/function-id.js";
|
6
7
|
import { useNFTContext } from "./provider.js";
|
7
8
|
import { getNFTInfo } from "./utils.js";
|
8
9
|
|
@@ -100,7 +101,7 @@ export function NFTDescription({
|
|
100
101
|
typeof descriptionResolver === "string"
|
101
102
|
? descriptionResolver
|
102
103
|
: typeof descriptionResolver === "function"
|
103
|
-
? descriptionResolver
|
104
|
+
? getFunctionId(descriptionResolver)
|
104
105
|
: undefined,
|
105
106
|
},
|
106
107
|
],
|
@@ -3,6 +3,7 @@
|
|
3
3
|
import { type UseQueryOptions, useQuery } from "@tanstack/react-query";
|
4
4
|
import type { JSX } from "react";
|
5
5
|
import type { ThirdwebContract } from "../../../../../contract/contract.js";
|
6
|
+
import { getFunctionId } from "../../../../../utils/function-id.js";
|
6
7
|
import { MediaRenderer } from "../../MediaRenderer/MediaRenderer.js";
|
7
8
|
import type { MediaRendererProps } from "../../MediaRenderer/types.js";
|
8
9
|
import { useNFTContext } from "./provider.js";
|
@@ -140,7 +141,7 @@ export function NFTMedia({
|
|
140
141
|
typeof mediaResolver === "object"
|
141
142
|
? mediaResolver
|
142
143
|
: typeof mediaResolver === "function"
|
143
|
-
? mediaResolver
|
144
|
+
? getFunctionId(mediaResolver)
|
144
145
|
: undefined,
|
145
146
|
},
|
146
147
|
],
|
@@ -3,6 +3,7 @@
|
|
3
3
|
import { type UseQueryOptions, useQuery } from "@tanstack/react-query";
|
4
4
|
import type { JSX } from "react";
|
5
5
|
import type { ThirdwebContract } from "../../../../../contract/contract.js";
|
6
|
+
import { getFunctionId } from "../../../../../utils/function-id.js";
|
6
7
|
import { useNFTContext } from "./provider.js";
|
7
8
|
import { getNFTInfo } from "./utils.js";
|
8
9
|
|
@@ -102,7 +103,7 @@ export function NFTName({
|
|
102
103
|
typeof nameResolver === "string"
|
103
104
|
? nameResolver
|
104
105
|
: typeof nameResolver === "function"
|
105
|
-
? nameResolver
|
106
|
+
? getFunctionId(nameResolver)
|
106
107
|
: undefined,
|
107
108
|
},
|
108
109
|
],
|
@@ -6,6 +6,7 @@ import { getChainMetadata } from "../../../../../chains/utils.js";
|
|
6
6
|
import { NATIVE_TOKEN_ADDRESS } from "../../../../../constants/addresses.js";
|
7
7
|
import { getContract } from "../../../../../contract/contract.js";
|
8
8
|
import { getContractMetadata } from "../../../../../extensions/common/read/getContractMetadata.js";
|
9
|
+
import { getFunctionId } from "../../../../../utils/function-id.js";
|
9
10
|
import { resolveScheme } from "../../../../../utils/ipfs.js";
|
10
11
|
import { useTokenContext } from "./provider.js";
|
11
12
|
|
@@ -117,7 +118,19 @@ export function TokenIcon({
|
|
117
118
|
}: TokenIconProps) {
|
118
119
|
const { address, client, chain } = useTokenContext();
|
119
120
|
const iconQuery = useQuery({
|
120
|
-
queryKey: [
|
121
|
+
queryKey: [
|
122
|
+
"_internal_token_icon_",
|
123
|
+
chain.id,
|
124
|
+
address,
|
125
|
+
{
|
126
|
+
resolver:
|
127
|
+
typeof iconResolver === "string"
|
128
|
+
? iconResolver
|
129
|
+
: typeof iconResolver === "function"
|
130
|
+
? getFunctionId(iconResolver)
|
131
|
+
: undefined,
|
132
|
+
},
|
133
|
+
] as const,
|
121
134
|
queryFn: async () => {
|
122
135
|
if (typeof iconResolver === "string") {
|
123
136
|
return iconResolver;
|
@@ -0,0 +1,148 @@
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
2
|
+
import { ANVIL_CHAIN } from "~test/chains.js";
|
3
|
+
import {} from "~test/react-render.js";
|
4
|
+
import { TEST_CLIENT } from "~test/test-clients.js";
|
5
|
+
import {
|
6
|
+
UNISWAPV3_FACTORY_CONTRACT,
|
7
|
+
USDT_CONTRACT,
|
8
|
+
} from "~test/test-contracts.js";
|
9
|
+
import { ethereum } from "../../../../../chains/chain-definitions/ethereum.js";
|
10
|
+
import { NATIVE_TOKEN_ADDRESS } from "../../../../../constants/addresses.js";
|
11
|
+
import { getFunctionId } from "../../../../../utils/function-id.js";
|
12
|
+
import { fetchTokenName, getQueryKeys } from "./name.js";
|
13
|
+
|
14
|
+
const client = TEST_CLIENT;
|
15
|
+
|
16
|
+
describe.runIf(process.env.TW_SECRET_KEY)("TokenName component", () => {
|
17
|
+
it("fetchTokenName should respect the nameResolver being a string", async () => {
|
18
|
+
const res = await fetchTokenName({
|
19
|
+
address: "thing",
|
20
|
+
client,
|
21
|
+
chain: ANVIL_CHAIN,
|
22
|
+
nameResolver: "tw",
|
23
|
+
});
|
24
|
+
expect(res).toBe("tw");
|
25
|
+
});
|
26
|
+
|
27
|
+
it("fetchTokenName should respect the nameResolver being a non-async function", async () => {
|
28
|
+
const res = await fetchTokenName({
|
29
|
+
address: "thing",
|
30
|
+
client,
|
31
|
+
chain: ANVIL_CHAIN,
|
32
|
+
nameResolver: () => "tw",
|
33
|
+
});
|
34
|
+
|
35
|
+
expect(res).toBe("tw");
|
36
|
+
});
|
37
|
+
|
38
|
+
it("fetchTokenName should respect the nameResolver being an async function", async () => {
|
39
|
+
const res = await fetchTokenName({
|
40
|
+
address: "thing",
|
41
|
+
client,
|
42
|
+
chain: ANVIL_CHAIN,
|
43
|
+
nameResolver: async () => {
|
44
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
45
|
+
return "tw";
|
46
|
+
},
|
47
|
+
});
|
48
|
+
|
49
|
+
expect(res).toBe("tw");
|
50
|
+
});
|
51
|
+
|
52
|
+
it("fetchTokenName should work for contract with `name` function", async () => {
|
53
|
+
const res = await fetchTokenName({
|
54
|
+
address: USDT_CONTRACT.address,
|
55
|
+
client,
|
56
|
+
chain: USDT_CONTRACT.chain,
|
57
|
+
});
|
58
|
+
|
59
|
+
expect(res).toBe("Tether USD");
|
60
|
+
});
|
61
|
+
|
62
|
+
it("fetchTokenName should work for native token", async () => {
|
63
|
+
const res = await fetchTokenName({
|
64
|
+
address: NATIVE_TOKEN_ADDRESS,
|
65
|
+
client,
|
66
|
+
chain: ethereum,
|
67
|
+
});
|
68
|
+
|
69
|
+
expect(res).toBe("Ether");
|
70
|
+
});
|
71
|
+
|
72
|
+
it("fetchTokenName should try to fallback to the contract metadata if fails to resolves from `name()`", async () => {
|
73
|
+
// todo: find a contract with name in contractMetadata, but does not have a name function
|
74
|
+
});
|
75
|
+
|
76
|
+
it("fetchTokenName should throw in the end where all fallback solutions failed to resolve to any name", async () => {
|
77
|
+
await expect(() =>
|
78
|
+
fetchTokenName({
|
79
|
+
address: UNISWAPV3_FACTORY_CONTRACT.address,
|
80
|
+
client,
|
81
|
+
chain: UNISWAPV3_FACTORY_CONTRACT.chain,
|
82
|
+
}),
|
83
|
+
).rejects.toThrowError(
|
84
|
+
"Failed to resolve name from both name() and contract metadata",
|
85
|
+
);
|
86
|
+
});
|
87
|
+
|
88
|
+
it("getQueryKeys should work without resolver", () => {
|
89
|
+
expect(getQueryKeys({ chainId: 1, address: "0x" })).toStrictEqual([
|
90
|
+
"_internal_token_name_",
|
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", nameResolver: "tw" }),
|
102
|
+
).toStrictEqual([
|
103
|
+
"_internal_token_name_",
|
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", nameResolver: fn }),
|
117
|
+
).toStrictEqual([
|
118
|
+
"_internal_token_name_",
|
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
|
+
nameResolver: fn,
|
138
|
+
}),
|
139
|
+
).toStrictEqual([
|
140
|
+
"_internal_token_name_",
|
141
|
+
1,
|
142
|
+
"0x",
|
143
|
+
{
|
144
|
+
resolver: fnId,
|
145
|
+
},
|
146
|
+
]);
|
147
|
+
});
|
148
|
+
});
|