Skip to content

Commit 955155d

Browse files
feat: improve select wallet chain list and available tokens based on selected
1 parent cf67975 commit 955155d

File tree

10 files changed

+1117
-98
lines changed

10 files changed

+1117
-98
lines changed

packages/connectkit/bundle-analysis.html

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

packages/connectkit/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@rozoai/intent-pay",
33
"private": false,
4-
"version": "0.1.5-beta.2",
4+
"version": "0.1.5-beta.3",
55
"author": "RozoAI",
66
"homepage": "https://github.com/RozoAI/intent-pay",
77
"license": "BSD-2-Clause",
@@ -47,7 +47,7 @@
4747
"@albedo-link/intent": "^0.13.0",
4848
"@reown/appkit": "^1.7.0",
4949
"@rollup/plugin-typescript": "^12.1.2",
50-
"@rozoai/intent-common": "workspace:*",
50+
"@rozoai/intent-common": "0.1.6-beta.2",
5151
"@solana/spl-token": "^0.4.14",
5252
"@solana/wallet-adapter-base": "^0.9.27",
5353
"@solana/wallet-adapter-react": "^0.15.39",

packages/connectkit/src/components/DaimoPayModal/index.tsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ export const RozoPayModal: React.FC<{
8383
setSelectedStellarTokenOption,
8484
setSelectedDepositAddressOption,
8585
setSelectedWallet,
86+
setSelectedChainId,
8687
} = paymentState;
8788
const { paymentState: paymentFsmState } = useRozoPay();
8889

@@ -322,17 +323,34 @@ export const RozoPayModal: React.FC<{
322323
) {
323324
if (isEthConnected) {
324325
paymentState.setTokenMode("evm");
326+
// Preserve chainId from routeMeta if it exists (from SelectWalletChain),
327+
// otherwise use the current chain ID
328+
const chainId = context.routeMeta?.chainId ?? chain?.id;
325329
context.setRoute(ROUTES.SELECT_TOKEN, {
326330
event: "connected",
327331
walletId: connector?.id,
328-
chainId: chain?.id,
332+
chainId,
329333
address,
330334
});
331335
}
332336
}
333337
// eslint-disable-next-line react-hooks/exhaustive-deps
334338
}, [isEthConnected, context.route, connector?.id, chain?.id, address]);
335339

340+
// Extract chainId from routeMeta when navigating to SELECT_TOKEN
341+
useEffect(() => {
342+
if (context.route === ROUTES.SELECT_TOKEN && context.routeMeta?.chainId) {
343+
const chainId = context.routeMeta.chainId as number;
344+
setSelectedChainId(chainId);
345+
} else if (
346+
context.route !== ROUTES.SELECT_TOKEN &&
347+
context.route !== ROUTES.SELECT_WALLET_CHAIN
348+
) {
349+
// Clear selectedChainId when leaving SELECT_TOKEN or SELECT_WALLET_CHAIN
350+
setSelectedChainId(undefined);
351+
}
352+
}, [context.route, context.routeMeta, setSelectedChainId]);
353+
336354
useEffect(() => setMode(mode), [mode, setMode]);
337355
useEffect(() => setTheme(theme), [theme, setTheme]);
338356
useEffect(() => setCustomTheme(customTheme), [customTheme, setCustomTheme]);

packages/connectkit/src/components/Pages/SelectToken/index.tsx

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -107,16 +107,18 @@ export default function SelectToken() {
107107
show={effectiveTokenMode}
108108
excludeLogos={["stellar"]}
109109
/>
110-
<OptionsList
111-
requiredSkeletons={3}
112-
isLoading={isLoading}
113-
options={optionsList}
114-
scrollHeight={
115-
isAnotherMethodButtonVisible && isMobileFormat ? 225 : 300
116-
}
117-
orDivider={isAnotherMethodButtonVisible}
118-
hideBottomLine={!isAnotherMethodButtonVisible}
119-
/>
110+
{(optionsList.length > 0 || isLoading) && (
111+
<OptionsList
112+
requiredSkeletons={3}
113+
isLoading={isLoading}
114+
options={optionsList}
115+
scrollHeight={
116+
isAnotherMethodButtonVisible && isMobileFormat ? 225 : 300
117+
}
118+
orDivider={isAnotherMethodButtonVisible}
119+
hideBottomLine={!isAnotherMethodButtonVisible}
120+
/>
121+
)}
120122
{showInsufficientBalance && !noConnectedWallet && (
121123
<InsufficientBalance onRefresh={refreshOptions} />
122124
)}
@@ -179,7 +181,6 @@ function InsufficientBalance({
179181
>
180182
{isRefreshing ? "Refreshing..." : "Refresh Balance"}
181183
</Button>
182-
<SelectAnotherMethodButton />
183184
</ModalContent>
184185
);
185186
}

packages/connectkit/src/components/Pages/SelectWalletChain/index.tsx

Lines changed: 87 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1-
import React from "react";
1+
import {
2+
base,
3+
bsc,
4+
Chain,
5+
ethereum,
6+
polygon,
7+
rozoSolana,
8+
supportedTokens,
9+
} from "@rozoai/intent-common";
10+
import React, { useCallback, useMemo } from "react";
211
import { usePayContext } from "../../../hooks/usePayContext";
312

413
import { ModalContent, PageContent } from "../../Common/Modal/styles";
@@ -21,53 +30,91 @@ const SelectWalletChain: React.FC = () => {
2130
usePayContext();
2231
const { selectedWallet } = paymentState;
2332

24-
if (selectedWallet == null) {
25-
return <PageContent></PageContent>;
26-
}
33+
// Get available chain IDs from supportedTokens (must be called before early returns)
34+
const availableChainIds = useMemo(
35+
() => new Set(Array.from(supportedTokens.keys())),
36+
[]
37+
);
2738

2839
// Narrow the wallet type to include solanaConnectorName.
29-
const wallet = selectedWallet as WalletProps;
40+
const wallet = selectedWallet as WalletProps | undefined;
3041

31-
// If wallet only supports one chain, skip this page (fallback safety)
32-
if (!wallet.solanaConnectorName) {
42+
// Define chain options with their icons (must be called before early returns)
43+
const chainConfigs = useMemo(
44+
() => [
45+
{
46+
chain: ethereum,
47+
icon: <Ethereum key="ethereum" />,
48+
supported: availableChainIds.has(ethereum.chainId),
49+
},
50+
{
51+
chain: base,
52+
icon: <Base key="base" />,
53+
supported: availableChainIds.has(base.chainId),
54+
},
55+
{
56+
chain: polygon,
57+
icon: <Polygon key="polygon" />,
58+
supported: availableChainIds.has(polygon.chainId),
59+
},
60+
{
61+
chain: bsc,
62+
icon: <BinanceSmartChain key="bnb" />,
63+
// Phantom doesn't support BSC, so we don't show it for Phantom
64+
supported:
65+
availableChainIds.has(bsc.chainId) && wallet?.id !== "app.phantom",
66+
},
67+
{
68+
chain: rozoSolana,
69+
icon: <Solana key="solana" />,
70+
supported: availableChainIds.has(rozoSolana.chainId),
71+
},
72+
],
73+
[availableChainIds, wallet?.id]
74+
);
75+
76+
// Filter to only supported chains
77+
const supportedChains = useMemo(
78+
() => chainConfigs.filter((config) => config.supported),
79+
[chainConfigs]
80+
);
81+
82+
// Handle chain selection
83+
const handleSelect = useCallback(
84+
(chain: Chain) => {
85+
if (!wallet) return;
86+
if (chain.type === "evm") {
87+
setPendingConnectorId(wallet.id);
88+
setRoute(ROUTES.CONNECT, { chainId: chain.chainId });
89+
} else if (chain.type === "solana") {
90+
setSolanaConnector(wallet.solanaConnectorName);
91+
setRoute(ROUTES.SOLANA_CONNECTOR, { chainId: chain.chainId });
92+
}
93+
},
94+
[wallet, setPendingConnectorId, setRoute, setSolanaConnector]
95+
);
96+
97+
const options = useMemo(
98+
() =>
99+
supportedChains.map((config) => ({
100+
id: `chain-${config.chain.chainId}`,
101+
title: config.chain.name,
102+
icons: [config.icon],
103+
iconsPosition: "left" as const,
104+
onClick: () => handleSelect(config.chain),
105+
})),
106+
[supportedChains, handleSelect]
107+
);
108+
109+
if (selectedWallet == null) {
33110
return <PageContent></PageContent>;
34111
}
35112

36-
function handleSelect(chain: "evm" | "solana") {
37-
if (chain === "evm") {
38-
setPendingConnectorId(wallet.id);
39-
setRoute(ROUTES.CONNECT);
40-
} else {
41-
setSolanaConnector(wallet.solanaConnectorName);
42-
setRoute(ROUTES.SOLANA_CONNECTOR);
43-
}
113+
// If wallet only supports one chain, skip this page (fallback safety)
114+
if (!wallet || !wallet.solanaConnectorName) {
115+
return <PageContent></PageContent>;
44116
}
45117

46-
const options = [
47-
{
48-
id: "ethereum",
49-
title: "Ethereum",
50-
icons: [<Ethereum key="ethereum" />],
51-
rightIcons: [
52-
<Base key="base" />,
53-
<Polygon key="polygon" />,
54-
// Phantom doesn't support BSC, so we don't show it for Phantom
55-
...(wallet.id !== "app.phantom"
56-
? [<BinanceSmartChain key="bnb" />]
57-
: []),
58-
],
59-
iconsPosition: "left" as const,
60-
onClick: () => handleSelect("evm"),
61-
},
62-
{
63-
id: "solana",
64-
title: "Solana",
65-
icons: [<Solana key="solana" />],
66-
iconsPosition: "left" as const,
67-
onClick: () => handleSelect("solana"),
68-
},
69-
];
70-
71118
return (
72119
<PageContent>
73120
<WalletPaymentSpinner

packages/connectkit/src/components/Pages/Solana/ConnectorSolana/index.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ const ConnectSolana: React.FC = () => {
1919
const solanaWallets = useWallet();
2020
const isConnected = solanaWallets.connected;
2121

22-
const { solanaConnector, setRoute, paymentState } = usePayContext();
22+
const { solanaConnector, setRoute, paymentState, routeMeta } =
23+
usePayContext();
2324
const { setTokenMode } = paymentState;
2425

2526
const selectedWallet = solanaWallets.wallets.find(
@@ -65,6 +66,8 @@ const ConnectSolana: React.FC = () => {
6566
const meta = {
6667
event: "wait-solana-connected",
6768
walletName: solanaWallets.wallet?.adapter.name,
69+
// Preserve chainId from routeMeta if it exists
70+
...(routeMeta?.chainId && { chainId: routeMeta.chainId }),
6871
};
6972
setTimeout(() => {
7073
setTokenMode("solana");

packages/connectkit/src/hooks/usePaymentState.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ export interface PaymentState {
142142
setPaymentWaitingMessage: (message: string | undefined) => void;
143143
tokenMode: "evm" | "solana" | "stellar" | "all";
144144
setTokenMode: (mode: "evm" | "solana" | "stellar" | "all") => void;
145+
selectedChainId: number | undefined;
146+
setSelectedChainId: (chainId: number | undefined) => void;
145147
setSelectedWallet: (wallet: WalletConfigProps | undefined) => void;
146148
setSelectedWalletDeepLink: (deepLink: string | undefined) => void;
147149
setSelectedExternalOption: (
@@ -291,6 +293,10 @@ export function usePaymentState({
291293
"evm" | "solana" | "stellar" | "all"
292294
>("evm");
293295

296+
const [selectedChainId, setSelectedChainId] = useState<number | undefined>(
297+
undefined
298+
);
299+
294300
const [txHash, setTxHash] = useState<string | undefined>(undefined);
295301
const [rozoPaymentId, setRozoPaymentId] = useState<string | undefined>(
296302
undefined
@@ -1300,6 +1306,8 @@ export function usePaymentState({
13001306
payParams: currPayParams,
13011307
tokenMode,
13021308
setTokenMode,
1309+
selectedChainId,
1310+
setSelectedChainId,
13031311
generatePreviewOrder,
13041312
isDepositFlow,
13051313
paymentWaitingMessage,

packages/connectkit/src/hooks/useTokenOptions.tsx

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export function useTokenOptions(mode: "evm" | "solana" | "stellar" | "all"): {
2828
setSelectedTokenOption,
2929
setSelectedSolanaTokenOption,
3030
setSelectedStellarTokenOption,
31+
selectedChainId,
3132
} = paymentState;
3233

3334
const optionsList: Option[] = [];
@@ -86,45 +87,69 @@ export function useTokenOptions(mode: "evm" | "solana" | "stellar" | "all"): {
8687
})();
8788

8889
if (shouldIncludeEvm) {
90+
// Filter EVM options by selectedChainId if provided
91+
const evmOptionsRaw = walletPaymentOptions.options ?? [];
92+
const filteredEvmOptions = selectedChainId
93+
? evmOptionsRaw.filter(
94+
(option) => option.balance.token.chainId === selectedChainId
95+
)
96+
: evmOptionsRaw;
97+
8998
const evmOptions = walletPaymentOptions.isLoading
9099
? []
91100
: getEvmTokenOptions(
92-
walletPaymentOptions.options ?? [],
101+
filteredEvmOptions,
93102
isDepositFlow,
94103
setSelectedTokenOption,
95104
setRoute
96105
);
97106
optionsList.push(...evmOptions);
98107
isLoading ||= walletPaymentOptions.isLoading;
99-
hasAnyData ||= (walletPaymentOptions.options?.length ?? 0) > 0;
108+
hasAnyData ||= filteredEvmOptions.length > 0;
100109
}
101110

102111
if (shouldIncludeSolana) {
112+
// Filter Solana options by selectedChainId if provided
113+
const solanaOptionsRaw = solanaPaymentOptions.options ?? [];
114+
const filteredSolanaOptions = selectedChainId
115+
? solanaOptionsRaw.filter(
116+
(option) => option.balance.token.chainId === selectedChainId
117+
)
118+
: solanaOptionsRaw;
119+
103120
const solanaOptions = solanaPaymentOptions.isLoading
104121
? []
105122
: getSolanaTokenOptions(
106-
solanaPaymentOptions.options ?? [],
123+
filteredSolanaOptions,
107124
isDepositFlow,
108125
setSelectedSolanaTokenOption,
109126
setRoute
110127
);
111128
optionsList.push(...solanaOptions);
112129
isLoading ||= solanaPaymentOptions.isLoading;
113-
hasAnyData ||= (solanaPaymentOptions.options?.length ?? 0) > 0;
130+
hasAnyData ||= filteredSolanaOptions.length > 0;
114131
}
115132

116133
if (shouldIncludeStellar) {
134+
// Filter Stellar options by selectedChainId if provided
135+
const stellarOptionsRaw = stellarPaymentOptions.options ?? [];
136+
const filteredStellarOptions = selectedChainId
137+
? stellarOptionsRaw.filter(
138+
(option) => option.balance.token.chainId === selectedChainId
139+
)
140+
: stellarOptionsRaw;
141+
117142
const stellarOptions = stellarPaymentOptions.isLoading
118143
? []
119144
: getStellarTokenOptions(
120-
stellarPaymentOptions.options ?? [],
145+
filteredStellarOptions,
121146
isDepositFlow,
122147
setSelectedStellarTokenOption,
123148
setRoute
124149
);
125150
optionsList.push(...stellarOptions);
126151
isLoading ||= stellarPaymentOptions.isLoading;
127-
hasAnyData ||= (stellarPaymentOptions.options?.length ?? 0) > 0;
152+
hasAnyData ||= filteredStellarOptions.length > 0;
128153
}
129154

130155
optionsList.sort((a, b) => {

packages/pay-common/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@rozoai/intent-common",
3-
"version": "0.1.6-beta.1",
3+
"version": "0.1.6-beta.2",
44
"description": "Intent Pay shared types and utilities",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

0 commit comments

Comments
 (0)