Skip to content

Commit ce45475

Browse files
authored
Cache custom chains internally (#3040)
1 parent c417bda commit ce45475

File tree

19 files changed

+127
-46
lines changed

19 files changed

+127
-46
lines changed

.changeset/dry-jobs-add.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"thirdweb": patch
3+
---
4+
5+
Fixes caching issue when using `defineChain`

packages/thirdweb/src/auth/core/verify-login-payload.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { defineChain } from "../../chains/utils.js";
1+
import { getCachedChain } from "../../chains/utils.js";
22
import { verifySignature } from "../verifySignature.js";
33
import { DEFAULT_LOGIN_STATEMENT, DEFAULT_LOGIN_VERSION } from "./constants.js";
44
import { createLoginMessage } from "./create-login-message.js";
@@ -126,7 +126,7 @@ export function verifyLoginPayload(options: AuthOptions) {
126126
signature: signature,
127127
address: payload.address,
128128
chain: payload.chain_id
129-
? defineChain(Number.parseInt(payload.chain_id))
129+
? getCachedChain(Number.parseInt(payload.chain_id))
130130
: undefined,
131131
client: options.client,
132132
});

packages/thirdweb/src/chains/utils.test.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import { defineChain as viemChain } from "viem";
22
import { describe, expect, it } from "vitest";
3+
import { ANVIL_CHAIN } from "../../test/src/chains.js";
4+
import { TEST_CLIENT } from "../../test/src/test-clients.js";
5+
import { ANVIL_PKEY_A, TEST_ACCOUNT_B } from "../../test/src/test-wallets.js";
6+
import { getRpcClient, prepareTransaction } from "../exports/thirdweb.js";
7+
import { toSerializableTransaction } from "../transaction/actions/to-serializable-transaction.js";
8+
import { privateKeyToAccount } from "../wallets/private-key.js";
39
import { defineChain } from "./utils.js";
410

511
describe("defineChain", () => {
@@ -29,4 +35,47 @@ describe("defineChain", () => {
2935
expect(thirdwebViem.nativeCurrency).toEqual(zoraViem.nativeCurrency);
3036
expect(thirdwebViem.rpc).toEqual(zoraViem.rpcUrls.default.http[0]);
3137
});
38+
39+
it("should not cache custom chains", async () => {
40+
const chain = defineChain({
41+
id: 123456789,
42+
name: "Test",
43+
rpc: "https://rpc.test.com",
44+
});
45+
expect(defineChain(123456789).rpc).not.toEqual(chain.rpc);
46+
});
47+
48+
it("should overwrite custom chains with same id", async () => {
49+
const oldChain = defineChain({
50+
id: ANVIL_CHAIN.id,
51+
name: "Test",
52+
rpc: "FAIL",
53+
}); // this should get ignored
54+
getRpcClient({ chain: oldChain, client: TEST_CLIENT });
55+
56+
const account = privateKeyToAccount({
57+
privateKey: ANVIL_PKEY_A,
58+
client: TEST_CLIENT,
59+
});
60+
const chain2 = defineChain({
61+
id: ANVIL_CHAIN.id,
62+
name: "Test2",
63+
rpc: ANVIL_CHAIN.rpc,
64+
}); // this should be the rpc used
65+
66+
const tx = prepareTransaction({
67+
to: TEST_ACCOUNT_B.address,
68+
value: 100n,
69+
chain: chain2,
70+
client: TEST_CLIENT,
71+
});
72+
73+
const serializableTransaction = await toSerializableTransaction({
74+
transaction: tx,
75+
from: account.address,
76+
});
77+
78+
await account.sendTransaction(serializableTransaction);
79+
expect(defineChain(1).rpc).not.toEqual(chain2.rpc);
80+
});
3281
});

packages/thirdweb/src/chains/utils.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import type {
1010
LegacyChain,
1111
} from "./types.js";
1212

13+
const CUSTOM_CHAIN_MAP = new Map<number, Chain>();
14+
1315
/**
1416
* Defines a chain with the given options.
1517
* @param options The options for the chain.
@@ -31,7 +33,10 @@ export function defineChain(
3133
options: number | ChainOptions | ViemChain | LegacyChain,
3234
): Chain {
3335
if (typeof options === "number") {
34-
return { id: options, rpc: `https://${options}.rpc.thirdweb.com` } as const;
36+
return {
37+
id: options,
38+
rpc: `https://${options}.rpc.thirdweb.com`,
39+
} as const;
3540
}
3641
if (isViemChain(options)) {
3742
return convertViemChain(options);
@@ -44,7 +49,23 @@ export function defineChain(
4449
if (!rpc) {
4550
rpc = `https://${options.id}.rpc.thirdweb.com`;
4651
}
47-
return { ...options, rpc } as const;
52+
const chain = { ...options, rpc } as const;
53+
CUSTOM_CHAIN_MAP.set(options.id, chain);
54+
return chain;
55+
}
56+
57+
/**
58+
* @internal
59+
*/
60+
export function getCachedChain(id: number) {
61+
if (CUSTOM_CHAIN_MAP.has(id)) {
62+
return CUSTOM_CHAIN_MAP.get(id) as Chain;
63+
}
64+
const chain = {
65+
id: id,
66+
rpc: `https://${id}.rpc.thirdweb.com`,
67+
} as const;
68+
return chain;
4869
}
4970

5071
function isLegacyChain(

packages/thirdweb/src/cli/commands/generate/generate.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
formatAbiItem,
66
parseAbiItem,
77
} from "abitype";
8-
import { defineChain } from "../../../chains/utils.js";
8+
import { getCachedChain } from "../../../chains/utils.js";
99
import { createThirdwebClient } from "../../../client/client.js";
1010
import { resolveAbiFromContractApi } from "../../../contract/actions/resolve-abi.js";
1111
import { getContract } from "../../../contract/contract.js";
@@ -26,7 +26,7 @@ export async function generate(input: ChainIdAndContract) {
2626
}
2727
const contract = getContract({
2828
client,
29-
chain: defineChain(Number.parseInt(chainId)),
29+
chain: getCachedChain(Number.parseInt(chainId)),
3030
address: contractAddress,
3131
});
3232
const abi = await resolveAbiFromContractApi(contract);

packages/thirdweb/src/pay/buyWithCrypto/getQuote.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Hash } from "viem";
2-
import { defineChain } from "../../chains/utils.js";
2+
import { getCachedChain } from "../../chains/utils.js";
33
import type { ThirdwebClient } from "../../client/client.js";
44
import { getContract } from "../../contract/contract.js";
55
import {
@@ -277,7 +277,7 @@ export async function getBuyWithCryptoQuote(
277277

278278
const swapRoute: BuyWithCryptoQuote = {
279279
transactionRequest: {
280-
chain: defineChain(data.transactionRequest.chainId),
280+
chain: getCachedChain(data.transactionRequest.chainId),
281281
client: params.client,
282282
data: data.transactionRequest.data as Hash,
283283
to: data.transactionRequest.to,
@@ -290,7 +290,7 @@ export async function getBuyWithCryptoQuote(
290290
contract: getContract({
291291
client: params.client,
292292
address: data.approval.tokenAddress,
293-
chain: defineChain(data.approval.chainId),
293+
chain: getCachedChain(data.approval.chainId),
294294
}),
295295
spender: data.approval?.spenderAddress,
296296
amountWei: BigInt(data.approval.amountWei),

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatSteps.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
TriangleDownIcon,
55
} from "@radix-ui/react-icons";
66
import { useMemo } from "react";
7-
import { defineChain } from "../../../../../../../chains/utils.js";
7+
import { getCachedChain } from "../../../../../../../chains/utils.js";
88
import type { ThirdwebClient } from "../../../../../../../client/client.js";
99
import { NATIVE_TOKEN_ADDRESS } from "../../../../../../../constants/addresses.js";
1010
import type { BuyWithFiatQuote } from "../../../../../../../pay/buyWithFiat/getQuote.js";
@@ -104,13 +104,13 @@ export function FiatSteps(props: {
104104
const isPartialSuccess = statusMeta?.progressStatus === "partialSuccess";
105105

106106
const toChain = useMemo(
107-
() => defineChain(toTokenMeta.chainId),
107+
() => getCachedChain(toTokenMeta.chainId),
108108
[toTokenMeta.chainId],
109109
);
110110

111111
const destinationChain = useMemo(() => {
112112
if (props.status?.status !== "NOT_FOUND" && props.status?.destination) {
113-
return defineChain(props.status?.destination.token.chainId);
113+
return getCachedChain(props.status?.destination.token.chainId);
114114
}
115115

116116
return undefined;
@@ -130,7 +130,7 @@ export function FiatSteps(props: {
130130
}, [toTokenMeta]);
131131

132132
const onRampChain = useMemo(
133-
() => defineChain(onRampTokenMeta.chainId),
133+
() => getCachedChain(onRampTokenMeta.chainId),
134134
[onRampTokenMeta.chainId],
135135
);
136136

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/fiat/FiatTxDetailsTable.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ExternalLinkIcon } from "@radix-ui/react-icons";
2-
import { defineChain } from "../../../../../../../chains/utils.js";
2+
import { getCachedChain } from "../../../../../../../chains/utils.js";
33
import type { ThirdwebClient } from "../../../../../../../client/client.js";
44
import { formatNumber } from "../../../../../../../utils/formatNumber.js";
55
import { useChainQuery } from "../../../../../../core/hooks/others/useChainQuery.js";
@@ -35,7 +35,7 @@ export function OnRampTxDetailsTable(props: {
3535
txHash?: string;
3636
};
3737
}) {
38-
const onRampChainQuery = useChainQuery(defineChain(props.token.chainId));
38+
const onRampChainQuery = useChainQuery(getCachedChain(props.token.chainId));
3939
const onrampTxHash = props.statusMeta?.txHash;
4040

4141
const lineSpacer = (

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/swap/SwapFlow.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useMemo, useState } from "react";
2-
import { defineChain } from "../../../../../../../chains/utils.js";
2+
import { getCachedChain } from "../../../../../../../chains/utils.js";
33
import type { ThirdwebClient } from "../../../../../../../client/client.js";
44
import { NATIVE_TOKEN_ADDRESS } from "../../../../../../../constants/addresses.js";
55
import type { BuyWithCryptoQuote } from "../../../../../../../pay/buyWithCrypto/getQuote.js";
@@ -28,12 +28,12 @@ export function SwapFlow(props: SwapFlowProps) {
2828
const quote = props.buyWithCryptoQuote;
2929

3030
const fromChain = useMemo(
31-
() => defineChain(quote.swapDetails.fromToken.chainId),
31+
() => getCachedChain(quote.swapDetails.fromToken.chainId),
3232
[quote],
3333
);
3434

3535
const toChain = useMemo(
36-
() => defineChain(quote.swapDetails.toToken.chainId),
36+
() => getCachedChain(quote.swapDetails.toToken.chainId),
3737
[quote],
3838
);
3939

packages/thirdweb/src/react/web/ui/ConnectWallet/screens/Buy/tx-history/BuyTxHistoryButton.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import styled from "@emotion/styled";
2-
import { defineChain } from "../../../../../../../chains/utils.js";
2+
import { getCachedChain } from "../../../../../../../chains/utils.js";
33
import type { ThirdwebClient } from "../../../../../../../client/client.js";
44
import { formatNumber } from "../../../../../../../utils/formatNumber.js";
55
import { ChainName } from "../../../../components/ChainName.js";
@@ -47,7 +47,7 @@ export function BuyTxHistoryButton(props: {
4747
>
4848
<TokenIcon
4949
client={props.client}
50-
chain={defineChain(props.txInfo.status.quote.toToken.chainId)}
50+
chain={getCachedChain(props.txInfo.status.quote.toToken.chainId)}
5151
size="md"
5252
token={{
5353
address: props.txInfo.status.quote.toToken.tokenAddress,
@@ -97,7 +97,7 @@ export function BuyTxHistoryButton(props: {
9797
}}
9898
>
9999
<ChainName
100-
chain={defineChain(props.txInfo.status.quote.toToken.chainId)}
100+
chain={getCachedChain(props.txInfo.status.quote.toToken.chainId)}
101101
size="xs"
102102
client={props.client}
103103
/>

0 commit comments

Comments
 (0)